作者:晖之月 | 来源:互联网 | 2023-10-11 09:35
publicclassMyEntryimplementsIBaseService{publicStringA(StringjsonStr)throwsException{UserI
public class MyEntry implements IBaseService{ public String A(String jsonStr) throws Exception{ UserInfo user = null; UserDetail userDetail = null; this.getUserMsg(user,userDetail ,jsonStr); if(null!= user){ this.B(user,userDetail); } return “”; } //此处需要事务 private String B(UserInfo user, UserDetail detail) throws DBException{ baseDao.saveObject(user); baseDao.saveObject(detail); } } 那么如果baseDao.saveObject(detail)异常,整个B方法全部回滚。没问题 但是 如果我在配置事务的时候仅仅对 name=“B”,并且不对A进行配置事务,如下:
那么如果baseDao.saveObject(detail)异常,方法B不能全部回滚(也就是说虽然baseDao.saveObject(detail)没有保存成功,但是baseDao.saveObject(user)保存成功了)
在 spring 中一共定义了六种事务传播属性,如下
PROPAGATION_REQUIRED – 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS – 支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY – 支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW – 新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED – 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER – 以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED – 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。 它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)
研究源码、调试程序得出结论: A如果没有受事务管理: 则线程内的connection 的 autoCommit为true。 B得到事务时事务传播特性依然生效,得到的还是A使用的connection,但是 不会改变autoCommit的属性。 所以B当中是按照每条sql进行提交的。
在一个Service内部,事务方法之间的嵌套调用,普通方法和事务方法之间的嵌套调用,都不会开启新的事务.是因为spring采用动态代理机制来实现事务控制,而动态代理最终都是要调用原始对象的,而原始对象在去调用方法时,是不会再触发代理了!
解决办法:
可以把方法B放到另外一个service或者dao,然后把这个server或者dao通过@Autowired注入到方法A的bean里面,这样即使方法A没用事务,方法B也可以执行自己的事务了。