在使用spring作为开发框架的时候,大家经常会遇到一个情况,在同一个类中,a函数去调用一个加了事务注解的b函数,这个时候,b函数上的事务是不生效的。
至于原因,相信大家都是知道的,就是因为这个时候,a调用b的时候,没有走代理类。
而要生效的话,我们需要去得到他的代理对象
总的来说,实现方案,就是不能让他直接内部调用,需要走代理对象去执行
具体实现方法
1.通过Lazy,把当前bean注入给自己
@Service
public class UserService {
@Autowired
@Lazy
private UserService self;
public void upsert(){
self.create(new User());
}
@Transactional
public void create(User user){
System.out.println("[UserService] create user");
}
}
开启debug日志级别,执行测试方法
@Test
public void upsert(){
userService.upsert();
}
2022-01-10 14:16:15.924 DEBUG 32298 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Creating new transaction with name [com.moensun.springboot2.mvc.service.UserService.create]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2022-01-10 14:16:15.928 DEBUG 32298 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3caf5c96] for JDBC transaction
2022-01-10 14:16:15.931 DEBUG 32298 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3caf5c96] to manual commit
[UserService] create user
2022-01-10 14:16:15.949 DEBUG 32298 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Initiating transaction commit
事务生效
2.暴露aopContext,通过aopContext获取代理对象
开启配置
@EnableAspectJAutoProxy(proxyTargetClass = true,exposeProxy = true)
@Service
public class UserService {
public UserService getSelf() {
return (UserService) AopContext.currentProxy();
}
public void upsert(){
getSelf().create(new User());
}
@Transactional
public void create(User user){
System.out.println("[UserService] create user");
}
}
2022-01-10 14:23:01.733 DEBUG 32368 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Creating new transaction with name [com.moensun.springboot2.mvc.service.UserService.create]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2022-01-10 14:23:01.737 DEBUG 32368 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@78d6c244] for JDBC transaction
2022-01-10 14:23:01.740 DEBUG 32368 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@78d6c244] to manual commit
[UserService] create user
2022-01-10 14:23:01.759 DEBUG 32368 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Initiating transaction commit
事务生效
当然还有其他的解决方案,比如不用动态代理,用静态代理。或者是直接编程式事务。这里我们解决的是这种基于注解的切面问题。不局限于@Transactional。上面的两种方式,都可以达到效果,但是,相对来说第二种方式,更加推荐一点,比较符合spring的思想。