@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 …