探索Java中private方法添加@Transactional事務(wù)未生效原因
現(xiàn)在產(chǎn)品期望用戶創(chuàng)建和保存邏輯分離:把User實(shí)例的創(chuàng)建和保存邏輯拆到兩個(gè)方法分別進(jìn)行。然后,把事務(wù)的注解 @Transactional 加在保存數(shù)據(jù)庫的方法上。
@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 (student.getRealname().equals("小明")) {
throw new RuntimeException("該用戶已存在");
}
}
}
執(zhí)行程序,異常正常拋出

事務(wù)未回滾

源碼解析
debug:

前一段是 Spring 創(chuàng)建 Bean 的過程。當(dāng) Bean 初始化之后,開始嘗試代理操作,這是從如下方法開始處理的:
AbstractAutoProxyCreator#postProcessAfterInitialization
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
繼續(xù) debug,直到
AopUtils#canApply
針對切面定義里的條件,確定這個(gè)方法是否可被應(yīng)用創(chuàng)建成代理。有段 methodMatcher.matches(method, targetClass) 判斷這個(gè)方法是否符合這樣的條件:
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
// ...
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}

從 matches() 調(diào)用到
AbstractFallbackTransactionAttributeSource#getTransactionAttribute
獲取注解中的事務(wù)屬性,根據(jù)屬性確定事務(wù)的策略。

接著調(diào)用到
computeTransactionAttribute
根據(jù)方法和類的類型確定是否返回事務(wù)屬性:

當(dāng)上圖中條件判斷結(jié)果為 true,則返回 null,表明該方法不會被代理,從而導(dǎo)致事務(wù)注解不會生效。
那到底是不是 true 呢?
條件1:allowPublicMethodsOnly()
AnnotationTransactionAttributeSource#publicMethodsOnly屬性值

publicMethodsOnly 是通過 AnnotationTransactionAttributeSource 的構(gòu)造方法初始化的,默認(rèn)為 true。

條件2:Modifier.isPublic()
根據(jù)傳入的 method.getModifiers() 獲取方法的修飾符,該修飾符是 java.lang.reflect.Modifier 的靜態(tài)屬性,對應(yīng)的幾類修飾符分別是:
- PUBLIC: 1
- PRIVATE: 2
- PROTECTED: 4
這里做了一個(gè)位運(yùn)算,只有當(dāng)傳入的方法修飾符是 public 類型的時(shí)候,才返回 true

綜上兩個(gè)條件,只有當(dāng)注解為事務(wù)方法為 public 才會被 Spring 處理。
修正
只需將修飾符從 private 改成 public,其實(shí)該問題 IDEA 也會告警,一般都會避免。

調(diào)用這個(gè)加了事務(wù)注解的方法,必須是調(diào)用被 Spring AOP 代理過的方法:不能通過類的內(nèi)部調(diào)用或通過 this 調(diào)用。所以我們的案例的StudentService,它Autowired了自身(StudentService)的一個(gè)實(shí)例來完成代理方法的調(diào)用。
到此這篇關(guān)于探索Java中private方法添加@Transactional事務(wù)未生效原因的文章就介紹到這了,更多相關(guān)Java private方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Cloud Alibaba Nacos Config進(jìn)階使用
這篇文章主要介紹了Spring Cloud Alibaba Nacos Config進(jìn)階使用,文中使用企業(yè)案例,圖文并茂的展示了Nacos Config的使用,感興趣的小伙伴可以看一看2021-08-08
完美解決IDEA Ctrl+Shift+f快捷鍵突然無效的問題
這篇文章主要介紹了完美解決IDEA Ctrl+Shift+f快捷鍵突然無效的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Java中從Integer到Date的轉(zhuǎn)換方法
這篇文章主要介紹了Java中integer怎么轉(zhuǎn)換date,在Java中,如果我們有一個(gè)Integer類型的數(shù)據(jù),想要將其轉(zhuǎn)換為Date類型,本文給大家介紹了實(shí)現(xiàn)方法,并通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-05-05
Spring自帶定時(shí)任務(wù)@Scheduled注解實(shí)例講解
這篇文章主要介紹了Spring自帶定時(shí)任務(wù)@Scheduled注解的相關(guān)知識,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-06-06
盤點(diǎn)SpringBoot中@Async注解的遇到的坑點(diǎn)及解決辦法
SpringBoot是一個(gè)流行的Java開發(fā)框架,在異步編程方面,Spring Boot提供了@Async注解,它能夠讓方法異步執(zhí)行,然而,在使用@Async注解時(shí),有一些潛在的坑需要注意,本文將深入探討Spring Boot中使用@Async注解時(shí)可能遇到的8大坑點(diǎn),并提供相應(yīng)的解決方案2024-03-03

