spring的事务控制,嵌套调用时为何不起效
描述: 用spring管理service层事务,然后配置切面,
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="del*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="do*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="*" propagation="SUPPORTS" rollback-for="java.lang.Exception" />
</tx:attributes>
</tx:advice>
,满足这三种特征的service方法,能正常实现再异常时回滚。但是,我在service定义了另外一个没有带着个特征的方法,比如searchBrandName(){}
在这个方法里调用"update*"方法,未使用任何try catch,从控制台上看异常被抛出,但是事务却没回滚,请问这是为什么?难道说spring只能看到最终抛出异常的方法,被调用方法是不管的?
Spring 的事务传播级别:
PROPAGATION_REQUIRED: 如果存在一个事务, 则支持当前事务. 如果没有事务则开启一个新的事务.<--常用
PROPAGATION_SUPPORTS: 如果存在一个事务, 支持当前事务. 如果没有事务, 则非事务的执行.<--常用
PROPAGATION_MANDATORY: 如果已经存在一个事务, 支持当前事务. 如果没有一个活动的事务, 则抛出异常.
PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务. 如果一个事务已经存在, 则将这个存在的事务挂起.<--嵌套事务
PROPAGATION_NOT_SUPPORTED: 总是非事务地执行, 并挂起任何存在的事务
PROPAGATION_NEVER: 总是非事务地执行, 如果存在一个活动事务, 则抛出异常
PROPAGATION_NESTED: 如果一个活动的事务存在, 则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行.
PROPAGATION_REQUIRES_NEW 和PROPAGATION_NESTED的区别主要是:
PROPAGATION_NESTED:这个事务的提交和回滚是依赖于外层事务的是否提交
PROPAGATION_REQUIRES_NEW: 只与自身的事务状态有关, 事务结束即被提交, 不依赖与外部的事务状态.
@Override
public List<BrandMapping> searchBrandName(String brandName) {
List<BrandMapping> brandMappingList = brandService.findBrand(brandName);
for (int i = 0; i < brandMappingList.size(); i++) {
BrandMapping brandMapping = brandMappingList.get(i);
// 调用update方法
updateSte(brandMapping, i);
return brandService.findBrand(brandName);
}
public void updateSte(BrandMapping brandMapping, int i) throws Exception{
brandMapping.setBrandName("测试测试...");
// 操作数据库
brandService.updateSte(brandMapping);
if (i == 3){
// 模拟异常出现
i = 1/ 0;
}
}
以上代码实现发现, updateSte() 方法中并没有事务的, 也就是说这种方式是不支持的,原因是searchBrandName()通过this调用本类的方法,这个方法并不是经过spring代理对象调用,所以AOP的切入是没有的。
解决办法:自己手动开启事务
@Autowired
private DataSourceTransactionManager txManagerGoods;
@Override
public List<BrandMapping> searchBrandName(String brandName) {
List<BrandMapping> brandMappingList = brandService.findBrand(brandName);
for (int i = 0; i < brandMappingList.size(); i++) {
BrandMapping brandMapping = brandMappingList.get(i);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);// 事物隔离级别,开启新事务
TransactionStatus status = txManagerGoods.getTransaction(def); // 获得事务状态
try {
updateSte(brandMapping, i);
txManagerGoods.commit(status);
} catch (Exception e) {
// e.printStackTrace();
txManagerGoods.rollback(status);
}
}
return brandService.findBrand(brandName);
}
public void updateSte(BrandMapping brandMapping, int i) throws Exception{
brandMapping.setBrandName("测试测试...");
brandService.updateSte(brandMapping);
if (i == 3){
i = 1/ 0;
}
}
代码中使用try catch 是因为spring 的事务如果是unchecked的异常的话, 事务都会被回滚的, 所以手动try catch 进行处理.