事务管理
大纲
Spring中事务的2种实现方式
四大事务隔离级别
七大事务传播行为
REQUIRED、REQUIRES_NEW、NESTED比较
Spring事务作用方法
Spring中事务的两种实现方式:
编程式事务管理(基于Java编程控制,很少使用)
-利用TransactionTemplate将多个DAO操作封装起来,可实现更细粒度的事务控制。
声明式事务管理(基于Spring的AOP配置控制,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务)
-基于TransactionProxyFactoryBean的方式.(很少使用)
需要为每个进行事务管理的类,配置一个TransactionProxyFactoryBean进行增强.
-基于XML配置(经常使用)
一旦配置好之后,类上不需要添加任何东西。
如果Action作为目标对象切入事务,需要在<aop:config>元素里添加proxy-target-class="true"属性。原因是通知Spring框架采用CGLIB技术生成具有事务管理功能的Action类。
-基于注解(配置简单,经常使用)
在applicationContext.xml中开启事务注解配置。(applicationContext.xml中只需定义Bean并追加以下元素)
<bean id="txManager" class="...">
<tx:annotation-driven transaction-manager="txManager"/>
四大事务隔离级别:
ISOLATION_READ_UNCOMMITTED:读未提交
ISOLATION_READ_COMMITTED:读已提交
ISOLATION_REPEATABLE_READ:可重复读
ISOLATION_SERIALIZABLE:串行化
常量来源于java.sql.Connection
详情可参考 https://www.cnblogs.com/lyrb/p/10747814.html
七大事务传播行为
REQUIRED: 如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务。该设置是最常用的设置。
SUPPORTS: 如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
MANDATORY: 如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
REQUIRES_NEW: 创建新事务,如果当前存在事务,则挂起当前事务。新事务执行完毕后,再继续执行老事务。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则挂起当前事务。
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED:如果当前存在事务,则在嵌套事务内执行,如果当前没有事务,则执行与REQUIRED类似的操作。拥有多个可以回滚的保存点,内层回滚不会对外层事务产生影响,只对DataSourceTransactionManager有效。
传播行为比较
1.REQUIRES_NEW和NESTED比较:
REQUIRES_NEW开启新事务,需要两次commit,外层事务不会影响内层事务的提交/回滚,但REQUIRES_NEW的内层事务的异常,会影响外层事务的回滚。
NESTED为父子事务,实际上是借助JDBC的SavePoint实现的,属于同一个事务,只要一次commit。NESTED在创建内层事务之前创建一个单独的保存点SavePoint,子事务只回滚到SavePoint,父事务可选择回滚或不回滚(catch住不抛出),所以内层NESTED方法抛出异常被回滚,如果在外层方法内catch住不抛出,则不会影响外层事务。父事务回滚子事务一定回滚。
2.REQUIRES_NEW和REQUIRED比较:
(1)不同的Service中调用方法:
REQUIRED方法调用REQUIRES_NEW方法,内层方法抛出异常,被catch后不抛出,外层事务可以正常提交;
如果REQUIRED方法调用REQUIRED,内层方法抛出异常,被catch后不抛出,后面的代码虽然可以执行下去,但外层事务最终还是会抛出rollback-only异常;
(2)同一个Service中调用方法:
如果REQUIRED方法调用REQUIRES_NEW方法,不会新建事务
不管REQUIRED方法调用REQUIRES_NEW方法还是REQUIRED方法(非事务方法更是适用),内层方法抛出异常时,外层只要catch住不抛出,外层事务就可以正常提交。
3.针对REQUIRED方法调用REQUIRES_NEW方法,不会新建事务的问题有两种解决方案:
(1)将两个方法写在不同的Service中
(2)方法写在同一个类中,但调用B方法的时候,将Service自己注入自己,用这个注入对象自己调用自己。
Spring事务作用方法
1.事务配置在业务逻辑接口层:
<aop:config proxy-target-class="false"> <aop:pointcut id="serviceOperation" expression="execution(* com.XX..*Service.*(..) " /> <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" /> </aop:config>
2.事物配置在业务逻辑实现层:
<aop:config proxy-target-class="true"> <aop:pointcut id="serviceOperation" expression="execution(* com.XX..*Service*.*(..) " /> <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" /> </aop:config>
一种说法是:Spring IoC的配置是为了避免直接与实现类交互,便于扩展,建议配置在接口上。
一种说法是:每个业务类一个接口有点麻烦呀,所以很多大牛都建议:“除非可以预见业务类将来一定会发生变化,否则不用写接口”,直接配置在实现类上。
https://blog.csdn.net/wangjunjun2008/article/details/53669951
https://www.cnblogs.com/dennyzhangdd/p/9602670.html
https://ask.csdn.net/questions/722300