@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: 随着右手旋律

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring框架,使用@Async注解可以将一个方法标记为异步执行,该方法会在一个新的线程执行。而@Transactional注解用于开启事务,用于保证数据的一致性。 当一个被@Async注解的方法调用一个被@Transactional注解的方法时,会出现事务失效的情况。这是因为@Transactional注解只能在当前线程开启事务,而异步方法是在新的线程执行的,与当前线程不在同一个线程,因此无法获取当前线程事务上下文。 为了解决这个问题,可以使用Spring提供的异步事务处理机制。具体来说,可以在@Async注解的方法上添加@Transaction注解,并设置propagation属性为REQUIRES_NEW,表示开启一个新的事务。这样,在异步方法执行的数据库操作就可以在新的事务进行,不会影响到当前线程事务。 举个例子: ``` @Service public class UserService { @Autowired private UserRepository userRepository; @Async @Transactional(propagation = Propagation.REQUIRES_NEW) public void updateUser(User user) { userRepository.save(user); } } ``` 在上述例子,updateUser方法使用了@Async和@Transactional注解,@Async注解表示该方法是异步执行的,@Transactional注解设置propagation属性为REQUIRES_NEW,表示开启一个新的事务。 总之,为了避免@Async修饰的方法@Transactional事务失效,需要在异步方法使用@Transaction注解开启一个新的事务

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值