一、Spring对MyBatis的整合思路

  • 作为Bean容器,Spring框架提供了IoC机制,可以接管所有组件的创建工作并进行依赖管理,因而整合的主要工作就是把MyBatis框架使用中所涉及的核心组件配置到Spring容器中,交给Spring来创建和管理。

二、Spring整合MyBatis的准备工作

  • 在项目中加入Spring、MyBatis及整合相关的JAR文件,下载地址
  • springbatch实战教程 springbatis_ssm

  • 所需JAR文件如下
  • springbatch实战教程 springbatis_sql_02

  • 建立开发目录结构,创建实体类
public class User implements java.io.Serializable{
	
		private Integer id;	//主键id
		private String userCode;	//用户编码
		private String userName;	//用户姓名	
		private String userPassword;	//用户密码
		private Integer gender;	//性别
		private Date birthday;	//出生日期
		private String phone;	//手机号码
		private String address;	//地址
		private Integer userRole;	//用户角色
		private Integer createdBy;	//创建者
		private Date creationDate;	//创建时间
		private Integer modifyBy;	//修改者
		private Date modifyDate;	//修改时间
		private String userRoleName;	//角色名称
	}
  • 创建数据访问接口
package cn.smbms.dao.user;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import cn.smbms.pojo.User;

public interface UserMapper {

	/**
	 * 获取用户记录数
	 * @return
	 * @throws Exception
	 */
	public int count()throws Exception;
	
	/**
	 * 查询用户列表(对象入参)
	 * @param user
	 * @return
	 * @throws Exception
	 */
	public List<User> getUserList(User user)throws Exception;
}
  • 配置sql映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
    
	<mapper namespace="cn.smbms.dao.user.UserMapper">
		<!--查询用户数 -->
		<select id="count" resultType="int">
			select count(1) as count from smbms_user
		</select>
		
		<!--查询用户列表  根据用户名和用户角色模糊查-->
		<select id="getUserList" resultMap="userList" parameterType="User"> 
			<!-- 使用resultType的方式实现联表多条件查 -->
			select u.*,r.roleName from smbms_user as u,smbms_role 
			as r  where u.userRole=r.id 
			<if test="userName!=null and userName!=''">
				and u.userName like CONCAT('%',#{userName},'%')
			</if>
			<if test="userRole!=null">
				and u.userRole=#{userRole} 
			</if>
			<!-- 分页查询 -->
			<!-- order by creationDate limit #{from},#{pageSize} -->
		</select> 
		<resultMap type="User" id="userList">
			<result property="userRoleName" column="roleName"/>
		</resultMap>
	</mapper>
  • 配置MyBatis配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration 
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "mybatis-3-config.dtd" >
<configuration>
	<!-- 类型别名 -->
	<typeAliases>
		<package name="cn.smbms.pojo"/>
	</typeAliases>
</configuration>

三、实现Spring对MyBatis的整合

1、配置数据源

<!--  使用Spring配置文件配置数据源dbcp-->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
		<property name="url">
			<value>
				<![CDATA[jdbc:mysql://localhost:3306/smbms?
					useUnicode=true&characterEncoding=utf-8]]>
			</value>
		</property>
		<property name="username" value="root"/>
		<property name="password" value="1998"/>
	</bean>

2、配置SqlSessionFactoryBean

<!-- 配置SqlSessionFactoryBean -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 引用数据源组件 -->
		<property name="dataSource" ref="dataSource"/>
		<!--  引用MyBatis配置文件中的配置-->
		<property name="configLocation" value="classpath:mybatis-config.xml"/>
		<!--  配置sql映射文件信息-->
		<property name="mapperLocations">
			<list>
				<value>classpath:cn/smbms/dao/**/*.xml</value>
			</list>
		</property>
		
	</bean>

注: 逐个列出所有的sql映射文件较繁琐,可以使用mapperLocations属性扫描式加载sql映射文件,其中“classpath:cn/smbms/dao/**/*.xml”表示扫描cn.smbms.dao包及其任意层级子包中,任意名称的xml类型文件。

3、使用SqlSessionTemplate实现数据库的操作

  • 简述:SqlSessionTemplate类实现了MyBatis的SqlSession接口,可以替换MyBatis中原有的SqlSession实现类提供数据库访问操作,使用SqlSessionTemplate可以更好的与Spring服务融合并简化部分流程化的工作,可以包含保证和当前Spring事务相关联,自动管理会话的生命周期,包括必要的关闭、提交和回滚操作。
  • 步骤
    (1)定义Mapper接口实现类
    (2)配置SqlSessionTemplate
    (3)配置DAO组件并注入sqlSessionTemplate实例
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
	</bean>
	<!-- 配置DAO组件并注入sqlSessionTemplate实例 -->
	<bean id="userMapper" class="cn.bdqn.dao.user.UserMapperImpl">
		<property name="sqlSession" ref="sqlSessionTemplate"/>
	</bean>

注:
(1)创建SqlSessionTemplate实例时,需要通过其构造方法注入SqlSessionFactory实例。
(2)与MyBatis中默认的SqlSession实现不同,SqlSessionTemplate是线程安全的,可以以单例模式配置并被多个DAO对象共用,而不被为每个DAO单独配置一个SqlSessionTemplate实例。

四、注入映射器实现

1、使用MapperFactory注入映射器

  • 例:
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
		<property name="mapperInterface" value="cn.smbms.dao.user.UserMapper"/>
		<property name="sqlSessionFactory" value="sqlSessionFactory"/>
	</bean>
  • 注:
    (1)配置DAO组件userMapper时,class属性不是某个实现类,而是MapperFactoryBean。
    (2)通过mapperInterface属性指定映射器,只能某个接口类型,不能是实现类。
    (3)MapperFactoryBean是SqlSessionDaoSupport的子类,需要通过setSqlSessionFactory()方法注入SqlSessionFactory实例已创建SqlSessionTemplate实例。
    (4)如果映射器对应的sql映射文件与映射器的类路径相同,该映射文件可以自动被SqlSessionFactory解析。在此情况下,配置SqlSessionFactoryBean可以不必指定sql映射文件的位置,反之如果映射与映射文件的类路径不同,则仍需在SqlSessionFactoryBean时明确指定映射文件的位置。

2、使用MapperScannerConfigurer注入映射器

  • 作用: 为了简化工作量,MyBatis-Spring中提供了MapperScannerConfigurer,它可以扫描包中的接口并将它们直接注册为MapperFactoryBean。
  • 例:
<!--使用MapperScannerConfigurer配置Dao  -->	
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="cn.smbms.dao"/>
	</bean>
  • 注:
    (1)basePackage属性指定了扫描的基准包MapperScannerConfigurer将递归扫描基准包(包括各层级子包)下所有接口。如果它们在sql映射文件中定义过,则将它们动态注册为MapperFactoryBean,如此即可批量产生映射器实现类。
    (2)basePackage属性中可包含多个包名,多个包名之间使用逗号隔开。
    (3)MapperScannerConfigurer会为所有 由它创建的映射器实现开启自动装配,也就是说,MapperScannerConfigurer创建的所有映射器实现都会被自动注入SqlSessionFactory实例。
例:	<!--使用MapperScannerConfigurer配置Dao  -->	
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!--(若在环境中出于不同目的配置了多个SqlSessionFactory实例),
			则需要显式指定所依赖的sqlSessionFactory实例-->
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
		<property name="basePackage" value="cn.smbms.dao"/>
	</bean>

(4)映射器被注册到Spring的容器时,Spring会根据其接口名称为其命名,默认规则是首字母小写的非完全限定类名,例如,UserMapper类型的组件会被默认命名为userMapper,为业务组件注入映射器如下。

<!-- 配置业务Bean并注入DAO实例 -->
	<bean id="userService" class="cn.smbms.service.user.UserServiceImpl">
		<property name="userMapper" ref="userMapper"/>
	</bean>

也可使用注解@Service标注业务实现类,使用@Autowired注解为业务实现类注入mapper。

五、为业务层添加声明式事务

1、配置声明式事务

  • 概述: Spring提供了声明式事务处理机制,它基于AOP实现,无需编写任何事务管理代码,所有的工作全在配置文件中完成。
  • 步骤:
    (1)导入aop、tx的jar,在Spring配置文件中引入命名空间
    (2)定义事务管理器
<!--定义事务管理器  -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
注:DataSourceTransactionManager时,要为其注入事先定义好的数据源组件。

(3)通过tx:advice标签配置事务增强,设定事务的属性,为不同的业务方法指定具体的事务规则。

<!-- 通过<tx:advice>标签为指定的事务管理器设置事务属性-->
	<tx:advice id="txAdvice" transaction-manager="txManager">	
		<!--定义属性,声明事务规则  -->
		<tx:attributes>
			<tx:method name="find*" propagation="SUPPORTS"/>
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="del*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="*" propagation="REQUIRED"/>
		</tx:attributes>
	</tx:advice>
  • 注:

(01)在<tx:advice>标签内可以设置 idtransaction-manager 属性,其中 transaction-manager 属性引用一个事务管理器Bean, transaction-manager 默认值是 transactionManager,如果事务管理器Bean的名称是 transactionManager,则可以不指定该属性。

(02)除了以上两个属性外,还可以通过<tx:attributes>子标签定制事务属性。事务属性通过<tx:method>标签进行设置,Spring支持对不同的方法设置不同的事务属性,所以可以为一个<tx:advice>配置多个<tx:method>

(03)<tx:method>标签中的name属性是必需的,用于指定匹配的方法;这里需要对方法名进行约定,可以使用通配符(*)。其他属性均为可选,用于指定具体的事务规则。

步骤(4)定义切面
例:

<!--定义切面  -->
	<aop:config>
		<!--定义切入点  -->
		<aop:pointcut id="serviceMethod"
			 expression="execution(* cn.smbms.service..*.*(..))"/>
		<!--将事务增强与切入点组合  -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
	</aop:config>

注:<aop:advisor>的advice-ref属性引用的是通过<tx:advice>标签定设定了事务属性的组件

2、使用注解实现声明式事务处理
(1) 在业务实现类上添加@Transactional注解即可为该类的所有业务方法统一添加事务处理;如果某一方法需要采用不同的事务规则,也可以在该业务方法上添加@Transactional注解单独设置。

(2)@Transactional注解也可以设置事务属性的值,默认的@Transactional设置如下
事务传播设置是--------------PROPAGATION_REQUIRED
事务隔离级别是--------------ISOLATION_DEFAULT
事务是------------------------- 读/写
事务超时默认是依赖于事务系统的,或者事务超时没有被支持任何RuntimeException将触发事务回滚,但是checked Exception将不触发事务回滚。

(3)@Transactional注解的属性如下
propagation 枚举型:---------------Propagation 可选的传播性设置
isolation 枚举型:--------------------Iaolation 可选的隔离性级别
readOnly 布尔型----------------------是否为只读型事务
timeout int型(单位:s)---------------事务超时
rollbackFor 一组class类的实例,必须是Throwable的子类-----------------------------------------------------------------------------一组异常类,遇到时必须进行回滚
rollbackForClassName--------------一组异常类名,遇到时必须进行回滚
noRollbackFor ------------------------一组异常类,遇到时必须不回滚
noRollbackForClassName---------一组异常类名,遇到时必须不回滚