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

  • Post author:
  • Post category:其他


@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方法才生效


原文链接:https://blog.csdn.net/cucgyfjklx/article/details/125910280