在本系列文章的《MyBatis与Spring集成示例续》中,介绍了Spring的编程式事务管理。网友 dabing69221提出讲一下MyBatis与Spring整合的声明式事务管理,今天就根据这一知识点,对上文的示例进行改进。
Spring的声明式事务管理是采用AOP(Aspect-Oriented Programming,面向切面编程)实现的。在编程式事务管理中,各事务处理代码实际上是相似的,这就造成了代码重复;而且编程式事务管理会造成事务管理代码和被管理的代码耦合,不符合软件工程中“高内聚、低耦合”的要求。若采用AOP,则可以避免以上缺陷。
Spring AOP需要引入的jar包请参考:http://blog.youkuaiyun.com/a352193394/article/details/7588851。
首先写一个DAO类,代码如下:
package com.abc.dao;
import com.abc.mapper.StudentMapper;
import com.abc.domain.Student;
public class StudentDao {
private StudentMapper studentMapper;
//studentMapper的setter和getter方法
public void setStudentMapper(StudentMapper studentMapper)
{
this.studentMapper = studentMapper;
}
public StudentMapper getStudentMapper()
{
return this.studentMapper;
}
public void save(Student student)
{
this.studentMapper.add(student);
int a = 1 / 0;
}
}
在此类中,有一个save方法用于保存学生,当然也可以添加其他方法。
接下来,我们要在Spring中应用AOP此类的方法提供事务管理,其配置如下(beans.xml):
<?xml version="1.0" encoding="utf8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd" default-autowire="byName" default-lazy-init="false"> <!--本示例采用DBCP连接池,应预先把DBCP的jar包复制到工程的lib目录下。 连接池配置如下--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost/courseman"/> <property name="username" value="courseman"/> <property name="password" value="abc123"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--dataSource属性指定要用到的连接池--> <property name="dataSource" ref="dataSource"/> <!--configLocation属性指定mybatis的核心配置文件--> <property name="configLocation" value="resources/configuration.xml"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="parentMapper" class="org.mybatis.spring.mapper.MapperFactoryBean" abstract="true"> <!--sqlSessionFactory属性指定要用到的SqlSessionFactory实例--> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean> <bean id="studentMapper" parent="parentMapper"> <!--mapperInterface属性指定映射器接口,用于实现此接口并生成映射器对象--> <property name="mapperInterface" value="com.abc.mapper.StudentMapper" /> </bean> <!--为studentDao注入studentMapper--> <bean id="studentDao" class="com.abc.dao.StudentDao"> <property name="studentMapper" ref="studentMapper" /> </bean> <!--配置事务处理策略,transaction-manager属性指定事务管理器。 若事务管理器bean的id即为transactionManager,则 transaction-manager的属性可以不指定--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--所有以find开头的方法都是只读的--> <tx:method name="find*" read-only="true" /> <tx:method name="save*" /> <!--其他方法使用默认事务策略--> <tx:method name="*" /> </tx:attributes> </tx:advice> <!-- AOP配置--> <aop:config> <!--pointcut元素定义一个切入点,execution中的第一个星号 用以匹配方法的返回类型,这里星号表明匹配所有返回类型。 com.abc.dao.*.*(..)表明匹配com.abc.dao包下的所有类的所有 方法--> <aop:pointcut id="myPointcut" expression="execution(* com.abc.dao.*.*(..))" /> <!--将定义好的事务处理策略应用到上述的切入点--> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" /> </aop:config> </beans>
由以上可看出,事务策略的配置主要是<tx:method />标签的配置。其中name属性是必须的,用以指定事务策略作用的目标方法。除read-only属性外,还有propagation和rollback-for等属性,用以指定事务的传播属性和触发事务回滚的异常。这里没有指定rollback-for属性,则Spring默认情况下只在发生了RuntimeException或Error异常时,才回滚事务。
在<aop:pointcut/>配置中,出现了execution表达式。关于此表达式的写法,请参考:http://lavasoft.blog.51cto.com/62575/172292/。
在StudentDao的save方法中,故意添加了一行代码int a = 1 / 0。这行代码会抛出ArithmeticException(这是一个RuntimeException),按照以上的配置,Spring会回滚事务。执行结果如下图所示:
如图中所示,事务已回滚,到数据库查询,学生记录也没有被插入。
本示例源码下载:http://down.51cto.com/data/857171。
MyBatis技术交流群:188972810,或扫描二维码:
【MyBatis学习笔记】系列之预备篇一:ant的下载与安装
【MyBatis学习笔记】系列之二:MyBatis增删改示例
【MyBatis学习笔记】系列之三:MyBatis的association示例
【MyBatis学习笔记】系列之四:MyBatis association的两种形式
【MyBatis学习笔记】系列之五:MyBatis与Spring集成示例
【MyBatis学习笔记】系列之六:MyBatis与Spring集成示例续
【MyBatis学习笔记】系列之七:MyBatis一对多双向关联
【MyBatis学习笔记】系列之八:MyBatis MapperScannerConfigurer配置
【MyBatis学习笔记】系列之九:MyBatis collection的两种形式
【MyBatis学习笔记】系列之十:MyBatis日志之Log4j示例
【MyBatis学习笔记】系列之十一:MyBatis多参数传递之注解方式示例
【MyBatis学习笔记】系列之十二:MyBatis多参数传递之默认命名方式示例
【MyBatis学习笔记】系列之十三:MyBatis多参数传递之Map方式示例
【MyBatis学习笔记】系列之十四:MyBatis中的N+1问题
【MyBatis学习笔记】系列之十五:MyBatis多参数传递之混合方式
【MyBatis学习笔记】系列之十六:Spring声明式事务管理示例
【MyBatis学习笔记】系列之十七:MyBatis多对多保存示例
【MyBatis学习笔记】系列之十八:MyBatis多对多关联查询示例
【MyBatis学习笔记】系列之十九:如何在MyBatis-3.2.7中使用Log4j2 rc2