Spring 事务管理
Spring事务实现主要有两种方法:
1、编程式事务:通过显式的编码来控制事务的边界和行为,而不是依赖框架提供的声明式事务管理机制(如注解或XML配置)。这种方式提供了对事务更直接的控制,允许开发者精确地决定何时开启、提交或回滚事务。
优点:
提供了极大的灵活性,开发者可以在代码中精确地控制事务的边界
适用于需要对事务管理进行复杂逻辑控制的场景。
缺点:
增加了代码量,使得业务逻辑与事务管理逻辑混杂在一起,降低了代码的可读性和可维护性。
容易出错,因为事务的开启、提交和回滚都需要手动编码实现,增加了开发者的负担。
2、声明式事务:是一种在不修改业务逻辑代码的情况下,通过配置或注解来管理和控制事务的方式。它允许开发者以一种非侵入性的方式来定义事务边界,从而使代码更加简洁、清晰且易于维护。Spring框架提供了两种声明式事务管理的方式:基于XML的配置和基于注解的配置(推荐使用注解方式,因其更为直观和方便)
优点:
主要通过配置或注解的方式实现,使事务管理与业务逻辑分离,提高了代码的清晰度和可维护性。
可以通过AOP(面向切面编程)机制灵活地应用到不同的方法上,不需要修改业务逻辑代码。
缺点:
相对于编程式事务管理,其灵活性较低。虽然可以通过一些高级配置满足复杂的事务需求,但在某些特定场景下可能不如编程式事务管理来得直接和强大。
声明式事务失效场景:
在使用Spring声明式事务时,可能会遇到一些导致事务失效的场景。以下是一些常见的导致事务不生效的情况:
-
异常被捕获且未重新抛出:
如果在一个被@Transactional注解的方法内部捕获了异常但没有重新抛出,那么Spring将认为该方法执行成功,从而提交事务。这会导致即使发生了错误,事务也不会回滚。 -
方法不是public的:
@Transactional注解只能应用于public方法上。如果将此注解用在非public方法(如protected、private或包级私有)上,则事务管理不会生效。 -
自调用问题:
当一个类中的方法A调用同一个类中的另一个带有@Transactional注解的方法B时,由于这是通过this引用进行的直接调用,而不是通过代理对象,因此事务控制不会起作用。解决办法是让方法A也标记为@Transactional,或者通过ApplicationContext获取当前bean的代理实例来调用方法B。 -
异常类型不匹配:
默认情况下,只有unchecked exceptions (即继承自RuntimeException和Error的异常)才会触发事务回滚。如果你抛出了一个checked exception(例如IOException),除非你明确指定了rollbackFor属性,否则事务不会自动回滚。 -
配置错误:
- 没有正确配置
<tx:annotation-driven />或@EnableTransactionManagement。 - 事务管理器没有正确定义或注入到Spring容器中。
- 使用了错误的事务管理器实现,比如对于JPA应该使用
JpaTransactionManager,而对于Hibernate则应使用HibernateTransactionManager。
- 没有正确配置
-
数据库引擎不支持事务:
确保使用的数据库表类型支持事务。例如,在MySQL中,MyISAM存储引擎不支持事务,而InnoDB支持。 -
传播行为设置不当:
如果方法的事务传播行为设置为NOT_SUPPORTED、NEVER或SUPPORTS等,那么这些设置可能导致事务不按预期工作。 -
异步方法:
在使用@Async注解的方法上同时使用@Transactional通常会导致事务失效,因为异步执行意味着方法调用发生在不同的线程中,而事务上下文不会跨线程传递。 -
final方法:
如果方法被声明为final,那么Spring AOP无法为其创建代理,从而导致事务管理失效。 -
缺少事务管理器:
必须确保Spring容器中有且只有一个PlatformTransactionManager类型的bean,否则可能因为找不到合适的事务管理器而导致事务不生效。
浙公网安备 33010602011771号