springboot为何可以直接用@Transactional注解
在Spring Boot中,当我们使用了spring-boot-starter-jdbc或spring-boot-starter-data-jpa依赖的时候,框架会自动默认分别注入DataSourceTransactionManager或JpaTransactionManager。所以我们不需要任何额外配置就可以用@Transactional注解进行事务的使用,我们通常在service层接口中使用@Transactional来对各个业务逻辑进行事务管理的配置
在声明事务时,只需要通过value属性指定配置的事务管理器名即可,例如:@Transactional(value="transactionManagerPrimary")
除了指定不同的事务管理器之后,还能对事务进行隔离级别和传播行为的控制
代码语言:javascript复制public enum Isolation {
DEFAULT(-1),
READ_UNCOMMITTED(1),
READ_COMMITTED(2),
REPEATABLE_READ(4),
SERIALIZABLE(8);
}
- DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是:READ_COMMITTED。
- READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
- READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
- REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
- SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 指定方法:通过使用isolation属性设置,例如:
@Transactional(isolation = Isolation.DEFAULT)
事务没有回滚的可能原因
- @Transactional注解修饰的函数中catch了异常,并没有往方法外抛。不过,也有一些复杂场景可能不一样
- @Transactional注解修饰的函数不是public类型
- 异常类型错误,如果有通过rollbackFor指定回滚的异常类型,那么抛出的异常与指定的是否一致。
- 数据源没有配置事务管理器
- 在一个类中调用自己的方法。建议分开写,互相调用
- 对应数据库使用的存储引擎不支持事务,比如:MyISAM
spring中编程式事务和声明式事务
Spring 的事务管理有 2 种方式: 传统的编程式事务管理,即通过编写代码实现的事务管理; 基于 AOP 技术实现的声明式事务管理。
- 编程式事务管理 编程式事务管理是通过编写代码实现的事务管理,灵活性高,但难以维护。
- 声明式事务管理 Spring 声明式事务管理在底层采用了 AOP 技术,其最大的优点在于无须通过编程的方式管理事务,只需要在配置文件中进行相关的规则声明,就可以将事务规则应用到业务逻辑中。 Spring 实现声明式事务管理主要有 2 种方式:
- 基于 XML 方式的声明式事务管理。
- 通过 Annotation 注解方式的事务管理。
显然声明式事务管理要优于编程式事务管理
@Transactional 事务不要滥用。事务会影响数据库的QPS(每秒查询率),另外使用事务的地方需要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等
本文仅供个人学习:参考来源:https://blog.didispace.com/transactional-not-rollback-20211115/