1. 方法非public
修饰
原理: Spring AOP代理(CGLIB或JDK动态代理)默认无法拦截非public方法。
示例:
java
@Service
public class UserService {
@Transactional
void updateUser() { // 非public方法
// 事务不会生效!
}
}
修复: 将方法改为public
。
2. 自调用(同一个类内部调用)
原理: 事务基于AOP代理,自调用绕过代理直接调用目标方法。
示例:
java
@Service
public class OrderService {
public void placeOrder() {
deductStock(); // 直接内部调用,事务失效
}
@Transactional
public void deductStock() {
// 事务不生效!
}
}
修复:
-
从其他Bean注入自身(通过
@Autowired
注入代理对象) -
使用
AopContext.currentProxy()
(需开启exposeProxy
)
3. 异常类型错误或被捕获
场景1:抛出非RuntimeException
/Error
原理: 默认只回滚RuntimeException
和Error
。
示例:
java
@Transactional
public void update() throws IOException {
if (error) throw new IOException(); // 检查型异常,不回滚!
}
修复:
添加rollbackFor
属性
java
@Transactional(rollbackFor = Exception.class)
场景2:异常被catch
后未重新抛出
原理: 事务管理器检测不到异常。
示例:
java
@Transactional
public void update() {
try {
db.update(...); // 抛出SQLException
} catch (Exception e) {
// 捕获后不抛出,事务提交!
}
}
修复: 在catch
中抛出RuntimeException
:
java
catch (Exception e) {
throw new RuntimeException(e);
}
4. 多线程环境下事务上下文丢失
原理: Spring事务信息存储在ThreadLocal
中,新线程无法继承上下文。
示例:
java
@Transactional
public void asyncUpdate() {
new Thread(() -> {
userDao.update(); // 子线程操作无事务控制!
}).start();
}
修复:
使用Spring的@Async
+ Transactional
(需配置异步任务执行器)
java
@Async
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void asyncTask() {
// 新事务生效
}
5. 数据库引擎不支持事务
原理: 如MySQL的MyISAM引擎不支持事务。
检查:
java
SHOW TABLE STATUS LIKE 'table_name'; -- 查看Engine类型
修复: 改用InnoDB引擎。
6. 嵌套事务传播配置错误
场景: 内层事务使用Propagation.NOT_SUPPORTED
示例:
java
@Transactional
public void outer() {
inner();
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void inner() {
// 挂起外层事务,操作无事务保护!
}
7. 非Spring管理Bean中使用@Transactional
原理: @Transactional
由Spring代理实现。
错误示例:
java
public class Util {
@Transactional // 未被Spring管理,注解无效
public static void save() { ... }
}