用自己的ip怎么查看dw8建设的网站,女生做网站主题有哪些,网站项目推广方案,十元精品店做网站Spring 事务机制回顾 Spring事务一个被讹传很广说法是#xff1a;一个事务方法不应该调用另一个事务方法#xff0c;否则将产生两个事务. 结果造成开发人员在设计事务方法时束手束脚#xff0c;生怕一不小心就踩到地雷。 其实这是不认识Spring事务传播机制而造成的误解一个事务方法不应该调用另一个事务方法否则将产生两个事务. 结果造成开发人员在设计事务方法时束手束脚生怕一不小心就踩到地雷。 其实这是不认识Spring事务传播机制而造成的误解Spring对事务控制的支持统一在TransactionDefinition类中描述该类有以下 几个重要的接口方法 除了事务的传播行为外事务的其他特性Spring是借助底层资源的功能来完成的Spring无非只充当个代理的角色。但是事务的传播行为却是Spring凭借自身的框架提供的功能 ;
Spring事务传播属性: 所谓事务传播行为就是多个事务方法相互调用时事务如何在这些方法间传播。Spring支持以下7种事务传播行为
Spring事务传播属性: 1.propagation-required: 支持当前事务,如果有就加入当前事务中;如果当前方法没有事务,就新建一个事务; 2.propagation-supports: 支持当前事务,如果有就加入当前事务中;如果当前方法没有事务,就以非事务的方式执行; 3.propagation-mandatory: 支持当前事务,如果有就加入当前事务中;如果当前没有事务,就抛出异常; 4.propagation-requires_new: 新建事务,如果当前存在事务,就把当前事务挂起;如果当前方法没有事务,就新建事务; 5.propagation-not-supported: 以非事务方式执行,如果当前方法存在事务就挂起当前事务;如果当前方法不存在事务,就以非事务方式执行; 6.propagation-never: 以非事务方式执行,如果当前方法存在事务就抛出异常;如果当前方法不存在事务,就以非事务方式执行; 7.propagation-nested: 如果当前方法有事务,则在嵌套事务内执行;如果当前方法没有事务,则与required操作类似; 前六个策略类似于EJB CMT第七个PROPAGATION_NESTED是Spring所提供的一个特殊变量。 它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为如Spring的DataSourceTransactionManager
在同一个类中一个方法调用另外一个有注解比如AsyncTransational的方法注解是不会生效的
代码示例: 例子中有两方法一个有Transational注解一个没有。如果调用了有注解的addPerson()方法会启动一个Transaction如果调用updatePersonByPhoneNo()因为它内部调用了有注解的addPerson()如果你以为系统也会为它启动一个Transaction那就错了实际上是没有的
Service
public class PersonServiceImpl implements PersonService {AutowiredPersonDao personDao;OverrideTransactionalpublic boolean addPerson(Person person) {boolean result personDao.insertPerson(person)0 ? true : false;return result;}Override//Transactionalpublic boolean updatePersonByPhoneNo(Person person) {boolean result personDao.updatePersonByPhoneNo(person)0 ? true : false;addPerson(person); //测试同一个类中Transactional是否起作用return result;}
}
原因
spring 在扫描bean的时候会扫描方法上是否包含Transactional注解如果包含spring会为这个bean动态地生成一个子类即代理类proxy代理类是继承原来那个bean的。此时当这个有注解的方法被调用的时候实际上是由代理类来调用的代理类在调用之前就会启动transaction。然而如果这个有注解的方法是被同一个类中的其他方法调用的那么该方法的调用并没有通过代理类而是直接通过原来的那个bean所以就不会启动transaction我们看到的现象就是Transactional注解无效。 为什么一个方法a()调用同一个类中另外一个方法b()的时候b()不是通过代理类来调用的呢可以看下面的例子为了简化用伪代码表示
Service
class A{Transactinalmethod b(){...}method a(){ //标记1b();}
}//Spring扫描注解后创建了另外一个代理类并为有注解的方法插入一个startTransaction()方法
class proxy$A{A objectA new A();method b(){ //标记2startTransaction();objectA.b();}method a(){ //标记3objectA.a(); //由于a()没有注解所以不会启动transaction而是直接调用A的实例的a()方法}
}当我们调用A的bean的a()方法的时候也是被proxy$A拦截执行proxy$A.a()标记3然而由以上代码可知这时候它调用的是objectA.a()也就是由原来的bean来调用a()方法了所以代码跑到了“标记1”。由此可见“标记2”并没有被执行到所以startTransaction()方法也没有运行。 解决的方法就简单了两种
把这两个方法分开到不同的类中把注解加到类名上面
结论:
在一个Service内部事务方法之间的嵌套调用普通方法和事务方法之间的嵌套调用都不会开启新的事务.
1. spring采用动态代理机制来实现事务控制而动态代理最终都是要调用原始对象的而原始对象在去调用方法时是不会再触发代理了
2. Spring的事务管理是通过AOP实现的其AOP的实现对于非final类是通过cglib这种方式即生成当前类的一个子类作为代理类然后在调用其下的方法时会判断这个方法有没有Transactional注解如果有的话则通过动态代理实现事务管理(拦截方法调用执行事务等切面)。当b()中调用a()时发现b()上并没有Transactional注解所以整个AOP代理过程(事务管理)不会发生。
附 使用AOP 代理后的方法调用执行流程