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

@Service
public class AbServiceImpl implements AbService {
    
    

    @Transactional(propagation = Propagation.MANDATORY)
    public void a(){
    
    

    }

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void b(){
    
    

    }

}
@Service
public class TransactionServiceImpl implements TransactionService {
    
    

    //从IOC容器中拿到代理对象,使动态代理生效
    @Autowired
    AbService abService; 

    @Transactional
    public void c(){
    
    
        //a,b,c三个方法在不同的类,使用动态代理的方式调用,这样可以实现三种Transactional事务设置各个都生效
        abService.a();
        abService.b();
    }

}

解决方案二

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

        <!-- 引入aop -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

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);
    }

}

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();
    }

}

总结

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




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

Lyric: 随着右手旋律

猜你喜欢

转载自blog.csdn.net/cucgyfjklx/article/details/125910280
今日推荐