今天在测试框架的时候,我想在一个service类的方法中调用 当前类的另一个方法(该方法通过@Transactional开启事务),这时候发现被调用类的事务并没有生效。
public boolean test1() { // xxx 业务逻辑
return test2();
}
@Transactional
public boolean test2() {
testMapper.insertSalary("test", UUID.randomUUID().toString()); int a = 10/0; return true;
}WHY? 搜索引擎一番查询之后,了解到问题的关键:
@Transactional 是基于aop生的代理对象开启事务的
PS:不了解代理模式的小伙伴,结尾有传送门
思路
1.spring 的事务是通过 aop 管理的
2.aop 会通过动态代理 为我们生成代理对象,aop 的功能(例如事务)都是在代理对象中实现的
aop 生成的代理类又在 spring 容器中,所以我们只要在 spring 容器中拿到当前这个bean 再去调用
test2()就可以开启事务了。
解决
import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;/**
* Spring的ApplicationContext的持有者,可以用静态方法的方式获取spring容器中的bean
*
*/@Componentpublic class SpringContextHolder implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
} public static ApplicationContext getApplicationContext() {
assertApplicationContext(); return applicationContext;
} @SuppressWarnings("unchecked") public static <T> T getBean(String beanName) {
assertApplicationContext(); return (T) applicationContext.getBean(beanName);
} public static <T> T getBean(Class<T> requiredType) {
assertApplicationContext(); return applicationContext.getBean(requiredType);
} private static void assertApplicationContext() { if (SpringContextHolder.applicationContext == null) { throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!");
}
}
} public boolean test1() { // xxx 业务逻辑
// 在spring容器中 获取当前类的代理类
return SpringContextHolder.getBean(TestS.class).test2();
}
@Transactional
public boolean test2() {
testMapper.insertSalary("test", UUID.randomUUID().toString()); int a = 10/0; return true;
}
作者:殷天文
链接:https://www.jianshu.com/p/cb649e6152b6
随时随地看视频