spring的两种常用事务传播属性说明

常用的两种传播属性:

1.REQUIRED 如果存在当前事务则用当前事务,如果不存在当前事务,则新建一个事务

2.REQUIRES_NEW 如果当前存在事务则挂起当前事务,开启一个新事务,新事务执行完毕后,唤醒之前挂起的事务,继续执行。如果不存在当前事务,则新建一个事务

第一种情况:

执行controller以后事务会回滚,两条数都插不进去。(propagation如果不写默认的是Propagation.REQUIRED,都是同一个事务,在第二个service抛出异常时,这个事务就会回滚)

第二种情况:

执行controller以后事务会回滚,Tuser会插入到数据表中,TOrder不会插入到数据表中。(在第一个service的事务传播属性是requires_new,在执行us.addUser()时,会把当前事务挂起,新创建一个事务,在user插入完成之后,事务提交,user数据入库,然后再释放挂起的事务,然后再执行os.addOrder(),抛出异常,事务回滚,order数据不会入库)

扫描二维码关注公众号,回复: 4836112 查看本文章

第三种情况

执行controller以后事务会回滚,两条数都插不进去。(在执行us.addUser()时,当前已经有事务了,addUser方法就会使用当前事务,进行执行,执行完成之后,事务不会提交,因为事务的作用方法还没有执行完成,然后会继续执行addOrder方法,addOrder方法会挂起当前事务,创建一个新事务,执行时出现异常,新建的事务就会回滚,order数据不会入库,然后释放之前挂起的事务,这个被释放的事务变成当前事务,由于addOrder方法里面没有捕捉异常,所以controller里面也会抛出异常,此时事务就会回滚,user数据也不会入库)

第四种情况

执行controller以后,Tuser会插入到数据表中,TOrder不会插入到数据表中。(在第一个service,addUser()方法执行完成后事务会正常提交,然后事务状态变成已完成isCompleted为true,在第二个service时,出现异常,事务回滚)

注意:spring事务是基于aop实现的。(只有来自外部方法的调用才会被aop代理捕获,类的内部方法调用不会被aop代理,即使此方法上面加了@Transactional注解)

示例:

执行完controller方法之后,Tuser会插入到数据表中,TOrder也会插入到数据表中。addUser方法上面的事务没有起作用,因为addUser方法是方法内部调用,不会被代理,所以事务不起作用。

改进方法:

如果是配置文件,则需要加入

<aop:aspectj-autoproxy expose-proxy="true"/><!—注解风格支持-->  

如果是boot方式

 @EnableAspectJAutoProxy(exposeProxy = true)

并加入依赖

<dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
                <version>1.5.6.RELEASE</version>
 </dependency>

 修改service方法

这样就可以正常执行事务回滚了.

Spring 是如何保证事务获取同一个Connection的

spring在某个线程第一次调用时候创建出connection之后在threadlocal中保存了它,

bindResource是在DataSourceTransactionManager.doBegin()方法中被调用的 

封装Map资源为:key值为DataSource生成actualKey,value值为DataSource获得的Connection对象封装后的ConnectionHolder

猜你喜欢

转载自blog.csdn.net/qianxiaopeng/article/details/82427689