失效场景
使用限制
1. 可继承(CGLIB代理)
反例:被final、static修饰
CGLIB是通过生成目标类子类的方式生成代理类的,被final、static修饰后,无法继承父类与父类的方法。
2. 被public修饰
不支持非public修饰的方法进行事务管理
3. 需要被Spring管理
都没有被Spring管理成为IOC容器中的一个bean,更别说被事务切面代理到了。
4. 需要通过bean调用
事务的管理是通过代理执行的方式生效的,如果是方法内部调用,将不会走代理逻辑,也就调用不到了。
5. 不支持多线程调用
事务信息是跟线程绑定的。
6. 数据库本身要支持事务
比如Mysql的Myisam存储引擎是不支持事务的,只有innodb存储引擎才支持。
7. 需要开启事务
在Springboot项目中已经不存在了,已经有DataSourceTransactionManagerAutoConfiguration默认开启了事务管理。
代码实例
@Slf4j
@Service
public class TestServiceImpl implements TestService {
@Resource
private TestMapper testMapper;
@Resource
private TestServiceImpl testService;
@Override
public void test() throws Exception {
testService.test2();
}
/**
* @description 本类方法调用本类事务方法会导致事务不生效
* 事务实现需要通过代理所以
* 调用的方法必须为public
* 且通过bean 调用
* @date 2024/11/26 18:22
**/
public void test0() throws Exception {
// 不可以回滚
// 本类方法调用本类事务方法会导致事务不生效
test1();
// 可以回滚
testService.test2();
}
/**
* @description 事物不支持多线程,需要用同步方法包裹
* @date 2024/11/27 10:00
**/
public synchronized void testMultiThreading() throws Exception {
testService.test1();
}
/**
* @description 这样是不行的,可能跳出同步方法但事务未提交,就有另一个线程来执行了
* @date 2024/11/27 10:03
**/
@Transactional
public synchronized void testMultiThreadingError() throws Exception {
test1();
}
/**
* @description 未指定异常,只会回滚Error,RuntimeException以及它们的子类
* @date 2024/11/26 17:57
**/
@Transactional
public void test1() throws Exception {
TestDO testDO = TestDO.builder().name("name").code("code").build();
testMapper.insert(testDO);
// 可以回滚
throw new Error();
// throw new RuntimeException();
// 不可以回滚
// throw new Exception();
}
/**
* @description 指定异常回滚, 会回滚Error,Exception以及它们的子类(Error不需要指定)
* @date 2024/11/26 17:58
**/
@Transactional(rollbackFor = Exception.class)
public void test2() throws Exception {
TestDO testDO = TestDO.builder().name("name").code("code").build();
testMapper.insert(testDO);
// 都可以回滚
// throw new RuntimeException();
throw new Error();
// throw new Exception();
}
}
结论
结论一:对于@Transactional可以保证RuntimeException,Error的回滚,如果想保证非RuntimeException错误的回滚,需要加上rollbackFor = Exception.class 参数。
结论二:try catch只是对异常是否可以被@Transactional 感知 到有影响。如果错误抛到切面可以感知到的地步,那就可以起作用。
结论三:由于REQUIRED属性,“两个事务”其实是一个事务,处理能力看报错时刻,是否添加了处理非RuntimeException的能力。