• @Transactional事务方法中包含多个同类事务方法,这些事务方法本身设置失效两种解决方案


    @Transactional事务方法中包含多个同类事务方法,这些事务方法本身设置失效两种解决方案

    问题背景

    1 @Transactional同类方法调用,不同设置的@Transactional失效两种解决方案
    2 伪代码举例说明问题

    • a,b,c三个方法在同一个类,为本方法调用
    • a,b,c三个方法的事务设置不同
    • 同类方法调用使 a,b 的Transactional事务设置失效,统一跟随 c 方法的事务设置,这并不是我们想要的结果
    public class TransactionServiceImpl implements TransactionService {
    
        @Transactional(propagation = Propagation.MANDATORY)
        public void a(){
    
        }
    
        @Transactional(isolation = Isolation.READ_COMMITTED)
        public void b(){
    
        }
    
        @Transactional
        public void c(){
            //1. a,b,c三个方法在同一个类,为本方法调用
            //2. a,b,c三个方法的事务设置不同
            //3. 同类方法调用使a,b的Transactional事务设置失效,统一跟随 c 方法的事务设置,这并不是我们想要的结果
            a();
            b();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    解决方案一

    1 因为事务注解是通过spring的IOC容器的控制反转实现的,直接调用本类方法,并没有使用spring的动态代理,所以可以更改为其他去调用其他类的方法,是动态代理生效

    @Service
    public class AbServiceImpl implements AbService {
    
        @Transactional(propagation = Propagation.MANDATORY)
        public void a(){
    
        }
    
        @Transactional(isolation = Isolation.READ_COMMITTED)
        public void b(){
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    @Service
    public class TransactionServiceImpl implements TransactionService {
    
        //从IOC容器中拿到代理对象,使动态代理生效
        @Autowired
        AbService abService; 
    
        @Transactional
        public void c(){
            //a,b,c三个方法在不同的类,使用动态代理的方式调用,这样可以实现三种Transactional事务设置各个都生效
            abService.a();
            abService.b();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    解决方案二

    1 使用spring自带获取动态代理对象的依赖

            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-aopartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2 在启动类使用@EnableAspectJAutoProxy(exposeProxy = true) 注解,开启aspect动态代理模式,对外暴露代理对象,可以代理当前对象,使@Asycn和@Transactional生效,所有动态代理使用aspectj创建,比JDK更多的好处是:没有开启接口也可以代理
    如果不开启这个注解,默认使用JDK的动态代理

    package com.lanran.transactional;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @EnableAspectJAutoProxy(exposeProxy = true)     //开启了aspect动态代理模式,对外暴露代理对象,可以代理当前对象,使@Asycn和@Transactional生效
    @MapperScan("com.lanran.transactional.dao")
    @SpringBootApplication
    public class TransactionalApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(TransactionalApplication.class, args);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3 拿到代理对象调用方法

    package com.lanran.transactional.service.impl;
    
    import com.lanran.transactional.service.TransactionService;
    import org.springframework.aop.framework.AopContext;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    /**
     * @Author suolong
     * @Date 2022/7/21 11:21
     * @Version 2.0
     */
    @Service
    public class TransactionServiceImpl implements TransactionService {
    
        @Transactional(propagation = Propagation.MANDATORY)
        public void a() {
    
        }
    
        @Transactional(isolation = Isolation.READ_COMMITTED)
        public void b() {
    
        }
    
        @Transactional
        public void c() {
            //从上下文中拿到代理对象
            TransactionServiceImpl  transactionService = (TransactionServiceImpl) AopContext.currentProxy();
            transactionService.a();
            transactionService.b();
        }
    
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36

    总结

    这个问题让我联想到@Async这个异步注解,原理也是一样的,同方法调用异步注解的方法,异步会失效,变成同步,只有调用其他类的@Async方法才生效




    作为程序员第 209 篇文章,每次写一句歌词记录一下,看看人生有几首歌的时间,wahahaha …

    Lyric: 随着右手旋律

  • 相关阅读:
    网络安全入门必知的靶场!
    windows上Qt5.15+openssl1.1.1+msvs2022静态编译32位版本的笔记
    c# --- 数据存储再识 与数组创建 与字符串
    ES6对象字面量的新功能
    基于python+Django+SVM算法模型的文本情感识别系统
    在 Python 中列出虚拟环境
    STM32之蜂鸣器实验
    ss-4.2 多个eureka集群案例
    React实现在线预览word报告/本地选择报告预览
    奇瑞新能源小蚂蚁,一款实用好看的居家小车
  • 原文地址:https://blog.csdn.net/cucgyfjklx/article/details/125910280