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


    #序
    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. 同一个类中的方法进行互相调用

    准备代码

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

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

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

    改下代码 试验下

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

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

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

    猜想

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

    验证下

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

    扩展

    transactionTemplate.executeWithoutResult

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

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

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

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

    TransactionSynchronization

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

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

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

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

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

    优化

    1. 我后来把事务的new 单独进行判断,把REQUIRES_NEW的 忽略了
    2. 多线程 之前进行过封装,分为了 1 在同一个事务中,一起提交 2 可以局部提交,局部完成,我根据之前的封装,继续判断,如果是 1 状态,我会执行这个完成操作,否则进行剔除
  • 相关阅读:
    Bazzite:专为 Steam Deck 和 PC 上的 Linux 游戏打造的发行版
    【两周学会FPGA】从0到1学习紫光同创FPGA开发|盘古PGL22G开发板学习之数码管动态显示(五)
    二叉树,平衡二叉树,B树,B+树,红黑树
    leetcode Top100 (5) 盛最多水的容器
    优雅退出在Golang中的实现
    阿里云基础知识小结
    优选商机+沃视获客+外呼系统+智能CRM
    筑牢数据隐私安全底线,ADSCOPE通过ISO隐私信息管理体系认证!
    教你快速解决unity无法添加脚本bug
    前缀树及计数排序、基数排序、排序算法拓展【十大经典排序】
  • 原文地址:https://blog.csdn.net/Huangjiazhen711/article/details/127801717