一、Spring对MyBatis的整合思路
- 作为Bean容器,Spring框架提供了IoC机制,可以接管所有组件的创建工作并进行依赖管理,因而整合的主要工作就是把MyBatis框架使用中所涉及的核心组件配置到Spring容器中,交给Spring来创建和管理。
二、Spring整合MyBatis的准备工作
- 在项目中加入Spring、MyBatis及整合相关的JAR文件,下载地址
- 所需JAR文件如下
- 建立开发目录结构,创建实体类
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>
标签内可以设置 id 和 transaction-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---------一组异常类名,遇到时必须不回滚