探索Java中private⽅法添加@Transactional事务未⽣效原因现在产品期望⽤户创建和保存逻辑分离:把User实例的创建和保存逻辑拆到两个⽅法分别进⾏。然后,把事务的注解 @Transactional 加在保存数据库的⽅法上。
@Service
public class StudentService {
@Autowired
private StudentMapper studentMapper;
@Autowired
private StudentService studentService;
public void saveStudent(String realname) throws Exception {
Student student = new Student();
student.setRealname(realname);
studentService.doSaveStudent(student);
}
@Transactional
private void doSaveStudent(Student student) throws Exception {
studentMapper.saveStudent(student);
if (Realname().equals("⼩明")) {
throw new RuntimeException("该⽤户已存在");
}
}
}
执⾏程序,异常正常抛出
事务未回滚
源码解析
debug:
前⼀段是 Spring 创建 Bean 的过程。当 Bean 初始化之后,开始尝试代理操作,这是从如下⽅法开始处理的:AbstractAutoProxyCreator#postProcessAfterInitialization
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = Class(), beanName);
if (ve(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
继续 debug,直到
AopUtils#canApply
针对切⾯定义⾥的条件,确定这个⽅法是否可被应⽤创建成代理。有段methodMatcher.matches(method, targetClass)判断这个⽅法是否符合这样的条件:public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
// ...
for (Class<?> clazz : classes) {
Method[] methods = AllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
从 matches() 调⽤到
AbstractFallbackTransactionAttributeSource#getTransactionAttribute
获取注解中的事务属性,根据属性确定事务的策略。
接着调⽤到
computeTransactionAttribute
根据⽅法和类的类型确定是否返回事务属性:
当上图中条件判断结果为 true,则返回 null,表明该⽅法不会被代理,从⽽导致事务注解不会⽣效。
那到底是不是 true 呢?
条件1:allowPublicMethodsOnly()
AnnotationTransactionAttributeSource#publicMethodsOnly属性值springboot其实就是spring
publicMethodsOnly 是通过 AnnotationTransactionAttributeSource 的构造⽅法初始化的,默认为 true。
条件2:Modifier.isPublic()
根据传⼊的Modifiers()获取⽅法的修饰符,该修饰符是 flect.Modifier 的静态属性,对应的⼏类修饰符分别是:
PUBLIC: 1
PRIVATE: 2
PROTECTED: 4
这⾥做了⼀个位运算,只有当传⼊的⽅法修饰符是 public 类型的时候,才返回 true
综上两个条件,只有当注解为事务⽅法为 public 才会被 Spring 处理。
修正
只需将修饰符从 private 改成 public,其实该问题 IDEA 也会告警,⼀般都会避免。
调⽤这个加了事务注解的⽅法,必须是调⽤被 Spring AOP 代理过的⽅法:不能通过类的内部调⽤或通过 this 调⽤。所以我们的案例的StudentService,它Autowired了⾃⾝(StudentService)的⼀个实例来完成代理⽅法的调⽤。
到此这篇关于探索Java中private⽅法添加@Transactional事务未⽣效原因的⽂章就介绍到这了,更多相关Java private⽅法内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论