Spring Boot 事务支持
Spring Boot 事务支持
参考链接
https://javabetter.cn/springboot/transaction.html
https://javaguide.cn/database/mysql/mysql-questions-01.html#mysql-事务
数据库 事务
一组操作,要么一起执行成功,要么一起执行失败
事务的特性
ACID
原子性(Atomicity)
- 事务执行的最小单位,保证操作全部执行完成或全部执行失败
一致性(Consistency)
- 事务执行前后,保持数据库的完整性(如转账人和收涨人的金额总和)
隔离性(Isolation)
- 各并发事务之间互不干扰
持久性(Durability)
- 事务提交后,数据库即使发生故障也不会导致修改数据的丢失
保证事务的 原子性、隔离性和持久性(手段)——保障了事务的 一致性(目的)
事务的隔离级别
未提交读(Read uncommitted)
- 最低的隔离级别,可能会出现脏读(dirty reads,可能读取到尚未提交的数据变更)、不可重复读或幻读
提交读(Read committed)
- 允许读取并发事务已经提交的数据,可以防止脏读,但可能会遇到不可重复读(non repeatable read,在一个事务内多次读取的同一数据可能不一致)和幻读
可重复读(Repeatable read)
- 除非数据被事务本身修改,否则事务对同一数据的多次读取结果相同,可以防止脏读和不可重复读,但可能发生幻读(phantom read,可以看作不可重复读的一种特殊情况,可重复读保证多次读取同一数据后 内容的一致,幻读 焦点在于多次执行查询语句时,可能出现记录总数的变化)
串行化(Serializable)
- 最严格的隔离级别,所有事物按照次序依次执行,防止了脏读、不可重复读和幻读的出现,该隔离级别的事务具有最高的安全性,但是串行执行导致了效率的急剧下降
MySQL数据库引擎中,InnoDB引擎支持事务,MyISAM引擎不支持
Spring对事务的支持
- 编程式事务(TransactionTemplate,TransactionManager)
- 业务代码中包含了额外的事务管理代码
- 声明式事务(@Transactional)
- AOP,实现事务管理和业务代码的解耦,在目标方法前 创建/加入事务,在目标方法执行后根据执行情况 进行提交/回滚
Spring事务管理核心,事务管理器 TransactionManager
public interface TransactionManager{}
子接口,编程式事务接口 ReactiveTransactionManager 和 声明式事务接口 PlatformTransactionManager
public interface PlatformTransactionManager extends TransactionManager{}
具体实现,JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)
声明式事务 @Transactional
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional{
//事务的传播行为
Propagation propagation() default Propagation.REQUIRED;
//事务的隔离级别
Isolation isolation() default Isolation.DEFAULT;
//事务超时时间
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
//事务是否只读
boolean readOnly() default false;
}
@Transactional 的使用
- 添加依赖
- Spring Boot 启动类上添加
@EnableTransactionManagement
注解,开启事务支持 - Service实现类的方法上加
@Transactional
注解 - https://blog.csdn.net/qq_37802465/article/details/113251279
事务的传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播
(例如:被调用方法 可以选择在当前事务中执行,也可以开启一个新的事务)
PROPAGATION_REQUIRED
- 默认的事务传播行为
- 如果外部方法没有开启事务,则被
Propagation.REQUIRED
修饰的内部方法开启自己的事务 - 如果外部方法开启事务,并且其被
Propagation.REQUIRED
修饰,则内部方法和外部方法共用同一事务,只要其中一个方法回滚,则整个事务都需要回滚
PROPAGATION_REQUIREDS_NEW
PROPAGATION_NESTED
PROPAGATION_MANDATORY
PROPAGATION_SUPPORTS
PROPAGATION_NOT_SUPPORTED
PROPAGATION_NEVER
事务的隔离级别
Spring的事务隔离级别
ISOLATION_DEFAULT
- 使用数据库默认的隔离级别
ISOLATION_READ_UNCOMMITED
ISOLATION_READ_COMMITED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE
事务的超时时间
事务所允许执行的最长时间,如果超时后还没有完成,则自动回滚;事务的执行时间如果太长,会导致该事务长时间占用数据库资源
事务的只读属性
MySQL(InnoDB)默认对每一个连接都启用autocommit模式,每一个SQL语句都会在一个单独的事务中执行,执行结束后自动提交
如果事务只是对数据库进行 读 操作,数据库可以利用事务的只读属性采取优化措施
事务的回滚策略
默认情况下,事务只在出现 运行时异常(Runtime Exception)和 Error 时回滚,遇到检查异常(Checked Exception,需要主动捕获处理或者向上抛出)不回滚
如果想要回滚特定异常类型
@Transsactional(rollbackFor = MyException.class)
补充
@Transactional 作用范围:类、方法、接口(不推荐)
@Transactional 只能对 权限修饰符为pubic 的方法使用
同一个类中,避免 直接在类内部调用 使用
@Transactional
注解的方法,这可能会导致事务失效public class MyService { public void methodA() { methodB(); } @Transactional public void methodB() { // 业务逻辑 } }
事务是通过
Spring AOP
代理实现的,同一个类中,通过this.methodB()
直接调用目标方法,而不是通过代理类进行调用,导致事务失效(https://heapdump.cn/article/5542790)