注解@Transactional

失效场景

image.png

使用限制

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的能力。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容