• 事务 还有这些用法,之前都不知道


    transationTemplate.execute 的写法 第一次 碰到,我之前是 controller -> biz -> service -> mapper 然后用 @Transation 注解搞定事务,至于 同一个类的 方法之间调用,在biz 层就规避了

    不懂就问

    首先 同一个类中 方法调用因为没有 走 aop 所以 事务不生效,这个应该没毛病吧

    问了人家,人家说 能解决 同一类中的 不同方法调用的 事务问题,我不太信。。验证下,如果能行,我以后加入

    Spring事务失效的场景

    1. 非public修饰
    2. final修饰也会失效, 动态代理需要重写方法才能生效事务, final修饰则无法重写
    3. static修饰也会失效
    4. 吞了异常, catch住没有抛给spring
    5. 抛了错误的异常, catch住手动抛Exception则不会回滚, 因为spirng事务只会处理RuntimeException和Error
    6. 同一个类中的方法进行互相调用

    准备代码

    1. public void a() {
    2. // transactionTemplate.execute(transactionStatus -> {
    3. // b();
    4. // c();
    5. // return true;
    6. // });
    7. Version version = new Version();
    8. version.setVersionName("test00");
    9. version.setProjectId(1L);
    10. versionService.save(version);
    11. b();
    12. c();
    13. }
    14. @Transactional(rollbackFor = Exception.class)
    15. public void b() {
    16. Version version = new Version();
    17. version.setVersionName("test01");
    18. version.setProjectId(1L);
    19. versionService.save(version);
    20. }
    21. @Transactional(rollbackFor = Exception.class)
    22. public void c() {
    23. Version version = new Version();
    24. version.setVersionName("test02");
    25. version.setProjectId(1L);
    26. versionService.save(version);
    27. int i = 1 / 0;
    28. }
    29. 复制代码

    第一次实验 嗯嗯 确实数据库插入了3条,事务没有生效嘛

    那按照大哥的说法 如果用他那种写法 就能保证事务了?

    改下代码 试验下

    1. public void a() {
    2. transactionTemplate.execute(transactionStatus -> {
    3. Version version = new Version();
    4. version.setVersionName("test00");
    5. version.setProjectId(1L);
    6. versionService.save(version);
    7. b();
    8. c();
    9. return true;
    10. });
    11. }
    12. 复制代码

    想想 如果是和大哥的想法一样 数据库应该是 没有插入,好 执行下

    嗯嗯 是的 确实没有数据库插入,但是为什么呢? 嗯嗯 大哥说得对

    猜想

    我第一想法 就是 它这么写 就相当于 我们之前biz 层 对 service 层的调用,自然而言 就保证了事务,毕竟实现了 不同类的调用嘛

    验证下

    1. @Nullable
    2. public T execute(TransactionCallback action) throws TransactionException {
    3. //判断transactionManager 是否为空 嗯嗯 没毛病
    4. Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
    5. //
    6. if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
    7. return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action);
    8. } else {
    9. TransactionStatus status = this.transactionManager.getTransaction(this);
    10. Object result;
    11. try {
    12. //执行 真正的代码
    13. result = action.doInTransaction(status);
    14. } catch (Error | RuntimeException var5) {
    15. this.rollbackOnException(status, var5);
    16. throw var5;
    17. } catch (Throwable var6) {
    18. this.rollbackOnException(status, var6);
    19. throw new UndeclaredThrowableException(var6, "TransactionCallback threw undeclared checked exception");
    20. }
    21. this.transactionManager.commit(status);
    22. return result;
    23. }
    24. }
    25. 复制代码

    扩展

    transactionTemplate.executeWithoutResult

    在看 transactionTemplate 方法的时候 发现一个 executeWithoutResult 方法,嗯嗯 他是干什么的

    看个名字应该是 没有返回值 嗯嗯

    1. default void executeWithoutResult(Consumer<TransactionStatus> action) throws TransactionException {
    2. this.execute((status) -> {
    3. action.accept(status);
    4. return null;
    5. });
    6. }
    7. 复制代码

    这 。。。不就是套了一层,返回个null么

    TransactionSynchronization

    1. public class DoTransactionCompletion implements TransactionSynchronization {
    2. private Runnable runnable;
    3. public DoTransactionCompletion(Runnable runnable){
    4. this.runnable = runnable;
    5. }
    6. @Override public void afterCompletion(int status) {
    7. if(status == TransactionSynchronization.STATUS_COMMITTED){
    8. this.runnable.run();
    9. }
    10. }
    11. }
    12. 复制代码
    1. public class TransactionUtils {
    2. public static void doAfterTransaction(DoTransactionCompletion doTransactionCompletion){
    3. if(TransactionSynchronizationManager.isActualTransactionActive()){
    4. TransactionSynchronizationManager.registerSynchronization(doTransactionCompletion);
    5. }
    6. }
    7. public static void main(String[] args) {
    8. TransactionUtils.doAfterTransaction(new DoTransactionCompletion(() -> {
    9. //事务成功才做的操作
    10. }));
    11. }
    12. }
    13. 复制代码

    例子是 上面的main方法 实现的是 只有事务成功才会执行的操作

    其余的可以自己进行判断status 进行控制

    但是并不完美,这个写法 是有问题的

    1. 如果使用了 @Transaction REQUIRES_NEW的话 就会出现误完成
    2. 如果里面有多线程 ,也会导致 异常

    优化

    1. 我后来把事务的new 单独进行判断,把REQUIRES_NEW的 忽略了
    2. 多线程 之前进行过封装,分为了 1 在同一个事务中,一起提交 2 可以局部提交,局部完成,我根据之前的封装,继续判断,如果是 1 状态,我会执行这个完成操作,否则进行剔除
  • 相关阅读:
    聊聊前端鉴权方案
    使用Jenkins部署Git仓库微服务项目
    神经网络——循环神经网络(RNN)
    Wireshark抓包工具解析HTTPS包
    微信公众号里怎么实现预订房间功能
    Excel中text函数5中常用方法
    YOLOv5模型训练及检测
    库函数和头文件
    go语言有哪些web框架
    c#装饰器模式详解
  • 原文地址:https://blog.csdn.net/m0_73311735/article/details/127786205