Spring事务管理配置示例
一.Spring事务特性
事务(Transaction)是并发控制的单元,是用户定义的一组操作序列。从数据库角度,就是一组SQL指令,如果执行过程中没有错误,则全部执行成功;如果执行出现错误,则撤销执行过的所有指令。Spring事务管理功能是基于底层DBMS本身的事务处理机制实现。
1.事务隔离级别
隔离级别是指若干个并发的事务之间的隔离程度。
ISOLATION_DEFAULT:默认值,使用数据库的默认隔离级别,就是ISOLATION_READ_COMMITTED。
ISOLATION_READ_UNCOMMITTED:表示一个事务可以读取另一个事务修改但还没有提交的数据。不能防止脏读,不可重复读和幻读,很少使用该隔离级别。
ISOLATION_READ_COMMITTED:表示一个事务只能读取另一个事务已经提交的数据。可以防止脏读。
ISOLATION_REPEATABLE_READ:表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。可以防止脏读和不可重复读。
ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,可以防止脏读、不可重复读以及幻读。严重影响程序的性能,通常不会用到该级别。
2.事务传播行为
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。
PROPAGATION_REQUIRED:默认值,如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则等价于PROPAGATION_REQUIRED。
3.事务超时
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。
4.事务只读属性
只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化。
二.方法一(基于@Transactional注解的事务)
支持@Transactional注解,编辑resources/spring/applicationContext_database.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 支持@Transactional注解事务,proxy-target-class=true通过CGlib创建子类来代理业务类 --> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> </beans>
UserServiceImpl增加@Transactional注解,编辑service/impl/UserServiceImpl.java
@Service public class UserServiceImpl implements UserService { @Resource private UserDOMapper userDao; @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED) public Boolean init() { UserDO A = new UserDO(); A.setUsername("Apple"); A.setPassword("123456"); userDao.insert(A); if (true) { throw new RuntimeException("SQL Exception"); } UserDO B = new UserDO(); B.setUsername("Amazon"); B.setPassword("abcdef"); userDao.insert(B); return true; } }
三.方法二(基于aop的事务,通过aop/tx命名空间配置事务)
Maven导入aop依赖,编辑pom.xml
<!-- aop事务 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.11</version> </dependency>
为service包下的init*()方法增加aop切面,编辑resources/spring/applicationContext_database.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 事务advice --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 与事务关联的方法名 --> <tx:method name="init*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!-- 通过aop定义事务切面 --> <aop:config> <aop:pointcut id="serviceMethod" expression="execution(* com.learn.spring.server.service..*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/> </aop:config> </beans>
四.验证事务
通过日志信息确认当UserServiceImpl.init()方法抛出RuntimeException时, 数据库执行了rollback()回滚。登录数据库,查询表中记录,证实记录未写入数据库,事务配置已生效。
作者:faramita2016
出处:http://www.cnblogs.com/faramita2016/
本文采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。