@Transactional
注解在 Spring 框架中用于声明式事务管理。当事务未按预期工作时,通常称为事务失效。事务失效的场景可能包括以下几种:
-
方法不是
public
的:
@Transactional
只能应用于public
方法。如果将其应用于private
、protected
或package-private
方法,事务将不会生效。 -
事务方法内部调用:
当同一个类中的非事务方法调用事务方法时,事务将不会生效。Spring AOP 代理无法拦截内部方法调用。public class MyService { public void nonTransactionalMethod() { transactionalMethod(); // 事务不会生效 } @Transactional public void transactionalMethod() { // 事务逻辑 } }
-
事务代理类型不正确:
默认情况下,Spring 使用 JDK 动态代理,这需要接口。如果类没有实现接口,Spring 将无法创建事务代理。使用proxyTargetClass = true
可以启用 CGLIB 代理,它不需要接口。@EnableTransactionManagement(proxyTargetClass = true)
-
默认的事务管理器未配置:
如果项目中有多个事务管理器而未指定默认的事务管理器,事务可能会失效。需要明确指定事务管理器。@Transactional(transactionManager = "yourTransactionManager")
-
Propagation 设置不当:
事务的传播行为配置不当可能导致事务失效。例如,如果设置了Propagation.NOT_SUPPORTED
,事务将不会生效。 -
异常类型不匹配:
默认情况下,Spring 仅在遇到未检查异常(继承自RuntimeException
)或错误(继承自Error
)时才会回滚事务。检查异常(继承自Exception
)不会触发回滚,除非明确配置。@Transactional(rollbackFor = Exception.class)
-
事务上下文丢失:
如果事务方法在新线程中执行(例如通过@Async
),事务上下文将丢失。 -
数据库不支持事务:
并非所有数据库都支持事务。如果使用的数据库不支持事务,@Transactional
将无效。 -
平台事务管理器配置不当:
如果平台事务管理器配置不当(例如,数据源未正确配置),事务也不会生效。
以下是一个综合示例,展示了如何正确配置 @Transactional
:
@Service
public class MyService {
private final MyRepository myRepository;
@Autowired
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
@Transactional(rollbackFor = Exception.class)
public void transactionalMethod() {
// 事务逻辑
myRepository.save(new MyEntity());
// 如果发生异常,事务将回滚
}
public void nonTransactionalMethod() {
transactionalMethod(); // 事务不会生效
}
}
通过理解和避免上述场景,可以确保 @Transactional
注解在 Spring 应用程序中正确地管理事务。