@Transactional在private方法上不生效,因Spring事务基于代理机制,仅public方法可被AOP拦截;private方法调用绕过代理,事务逻辑无法织入。
Spring事务基于代理机制,只有被代理对象的public方法才能被AOP拦截并织入事务逻辑。private方法无法被代理调用,即使加了@Transactional注解,也完全不会触发事务管理器。
private void doUpdate(),事务不会开启@Service类中,通过Spring容器注入调用TransactionTemplate手动控制事务,但会牺牲声明式事务的简洁性当一个@Service类里,methodA()(带@Transactional)调用本类的methodB()(也带@Transactional),实际执行的是this.methodB()——走的是原始对象调用,绕过了代理对象,事务不会传播。
methodB抛出异常,methodA的事务不回滚this指向当前实例,不是代理对象methodB开头打印this.getClass(),会看到类似UserService$$EnhancerBySpringCGLIB$$xxx以外的原始类名Spring默认只对RuntimeException及其子类、Error触发回滚。如果业务抛出的是Exception(比如IOException、自定义检查异常),且没显式配置rollbackFor,事务会正常提交。
@Transactional
public void transfer() throws BusinessException {
// ...
throw new BusinessException("余额不足");
}
@Transactional(rollbackFor = BusinessException.class)
public void transfer() throws BusinessException {
// ...
}
rollbackFor支持数组,可同时指定多个异常类型;noRollbackFor用于排除特定异常
事务失效有时和Spring无关,而是底层环境问题。最典型的是MySQL表使用MyISAM引擎——它根本不支持事务,无论注解怎么写都无效。
SHOW CREATE TABLE user;确认引擎是否为
InnoDB
JdbcTemplate.update()后又手动调用connection.commit(),会导致Spring事务管理器失去控制权propagation = Propagation.NOT_SUPPORTED,当前操作会挂起事务,也不受事务保护