@Transactional
注解标记的方法。TransactionInterceptor
负责管理事务的生命周期(开启、提交、回滚)。PlatformTransactionManager
实现类(如 DataSourceTransactionManager
)负责底层事务操作(如 JDBC 的 commit()
)。ThreadLocal
(TransactionSynchronizationManager
)存储当前事务的数据库连接,确保同一线程内多个操作共享同一事务。// 伪代码:事务拦截器逻辑
public Object invoke(MethodInvocation invocation) {
// 1. 获取事务属性(@Transactional配置)
TransactionAttribute txAttr = getTransactionAttribute(invocation.getMethod());
// 2. 获取事务管理器
PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 3. 开启事务(根据传播行为决定是否新建事务)
TransactionStatus status = tm.getTransaction(txAttr);
try {
// 4. 执行目标方法
Object result = invocation.proceed();
// 5. 提交事务
tm.commit(status);
return result;
} catch (Exception ex) {
// 6. 回滚事务(根据rollbackFor规则)
completeTransactionAfterThrowing(txAttr, status, ex);
throw ex;
}
}
问题:同类内部方法调用(未经过代理对象),事务注解失效。
@Service
public class UserService {
public void createUser() {
// 直接调用内部方法,事务不生效!
this.insertUser();
}
@Transactional
public void insertUser() {
// 插入用户到数据库
}
}
原因:this.insertUser()
是目标对象直接调用,未经过代理对象,事务拦截器未被触发。
解决:
AopContext
):@EnableAspectJAutoProxy(exposeProxy = true) // 启动类开启暴露代理
public class UserService {
public void createUser() {
UserService proxy = (UserService) AopContext.currentProxy();
proxy.insertUser(); // 通过代理对象调用
}
}
insertUser
放到另一个 Bean 中。问题:事务方法中捕获异常但未重新抛出,导致事务无法回滚。
@Transactional
public void updateUser() {
try {
userDao.update(user); // 可能抛出SQLException
} catch (SQLException e) {
// 捕获异常但未抛出,事务不会回滚!
log.error(“更新失败”, e);
}
}
原因:Spring 默认只对 RuntimeException
和 Error
回滚,且必须抛出异常。
解决:
RuntimeException
:catch (SQLException e) {
throw new RuntimeException(“更新失败”, e); // 触发回滚
}
@Transactional(rollbackFor = SQLException.class)
。问题:嵌套事务未按预期回滚。
@Transactional
public void outerMethod() {
userDao.insertUser();
try {
innerService.innerMethod();
} catch (Exception e) {
// 期望 innerMethod 回滚,但 outerMethod 继续提交
}
}
@Service
public class InnerService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {
userDao.updateUser(); // 抛出异常
}
}
现象:如果 innerMethod
抛出异常,innerMethod
的事务会回滚,但 outerMethod
的事务仍会提交(因为 innerMethod
的事务是独立的)。
解决:
outerMethod
在 innerMethod
失败时整体回滚,需在 outerMethod
中不捕获异常,或重新抛出异常。问题:使用 MyISAM 引擎的 MySQL 表不支持事务。
CREATE TABLE user (
id INT PRIMARY KEY
) ENGINE=MyISAM; – 不支持事务
现象:即使代码正确配置事务,操作仍不会回滚。
解决:使用 InnoDB 引擎:
CREATE TABLE user (…) ENGINE=InnoDB;
问题:@Transactional
标记在非 public 方法上,事务不生效。
@Service
public class UserService {
@Transactional
private void internalUpdate() { // 非 public 方法!
userDao.update(user);
}
}
原因:Spring 默认通过代理实现 AOP,无法拦截 private/protected 方法。
解决:
public
。@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
)。问题:新线程无法继承原线程的事务上下文。
@Transactional
public void process() {
new Thread(() -> {
userDao.updateUser(); // 新线程无法共享事务
}).start();
}
原因:TransactionSynchronizationManager
使用 ThreadLocal
,不同线程无法共享事务资源。
解决:
AbstractPlatformTransactionManager
的 DEBUG
日志)排查问题。@Transactional
时明确指定 rollbackFor
。public
修饰符。