1. 方法非public
修飾
原理:?Spring AOP代理(CGLIB或JDK動態代理)默認無法攔截非public方法。
示例:
@Service
public class UserService {@Transactionalvoid updateUser() { // 非public方法// 事務不會生效!}
}
修復:?將方法改為public
。
2. 自調用(同一個類內部調用)
原理:?事務基于AOP代理,自調用繞過代理直接調用目標方法。
示例:
@Service
public class OrderService {public void placeOrder() {deductStock(); // 直接內部調用,事務失效}@Transactionalpublic void deductStock() {// 事務不生效!}
}
修復:
-
從其他Bean注入自身(通過
@Autowired
注入代理對象) -
使用
AopContext.currentProxy()
(需開啟exposeProxy
)
3. 異常類型錯誤或被捕獲
場景1:拋出非RuntimeException
/Error
原理:?默認只回滾RuntimeException
和Error
。
示例:
@Transactional
public void update() throws IOException {if (error) throw new IOException(); // 檢查型異常,不回滾!
}
修復:
添加rollbackFor
屬性
@Transactional(rollbackFor = Exception.class)
場景2:異常被catch
后未重新拋出
原理:?事務管理器檢測不到異常。
示例:
@Transactional
public void update() {try {db.update(...); // 拋出SQLException} catch (Exception e) {// 捕獲后不拋出,事務提交!}
}
修復:?在catch
中拋出RuntimeException
:
catch (Exception e) {throw new RuntimeException(e);
}
4. 多線程環境下事務上下文丟失
原理:?Spring事務信息存儲在ThreadLocal
中,新線程無法繼承上下文。
示例:
@Transactional
public void asyncUpdate() {new Thread(() -> {userDao.update(); // 子線程操作無事務控制!}).start();
}
修復:
使用Spring的@Async
?+?Transactional
(需配置異步任務執行器)
@Async
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void asyncTask() {// 新事務生效
}
5. 數據庫引擎不支持事務
原理:?如MySQL的MyISAM引擎不支持事務。
檢查:
SHOW TABLE STATUS LIKE 'table_name'; -- 查看Engine類型
修復:?改用InnoDB引擎。
6. 嵌套事務傳播配置錯誤
場景:?內層事務使用Propagation.NOT_SUPPORTED
示例:
@Transactional
public void outer() {inner();
}@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void inner() {// 掛起外層事務,操作無事務保護!
}
7. 非Spring管理Bean中使用@Transactional
原理:?@Transactional
由Spring代理實現。
錯誤示例:
public class Util {@Transactional // 未被Spring管理,注解無效public static void save() { ... }
}