Spring-事务

原创
2021/02/18 15:04
阅读数 110

数据库事务是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

1 事务的特性

事务的4个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durabilily)。

特性 描述
原子性 一个事务的所有操作,要么全部完成,要么全部不完成,不能出现中间状态。
一致性 事务前后数据的完整性要保持一致。
隔离性 事务独立运行。并发的事务之间的数据保持隔离,互不影响。
持久性 事务提交后,对数据的改变是永久性的。

2 Spring事务管理

  • PlatformTransactionManager事务管理器
  • TransactionDefinition事务定义信息
  • TransactionStatus事务具体运行状态

2.1 事务管理器(PlatformTransactionManager)

定义了事务控制的核心标准。以下为几个常见的PlatformTransactionManager实现:

事务 说明
DataSourceTransactionManager 使用Spring JDBC或MyBatis进行持久化时使用
HibernateTransactionManager 使用Hibernate进行持久化时使用
JpaTransactionManager 使用JPA进行持久化时使用

2.2 事务定义信息(TransactionDefinition)

该接口主要定义了:事务的传播行为和隔离级别,及是否为只读事务以及超时配置。

2.2.1 事务的传播行为
类型 说明
PROPAGATION_REQUIRED 支持当前事务。没有则新建,有则加入
PROPAGATION_SUPPORTS 支持当前事务,没有则不使用事务
PROPAGATION_MANDATORY 支持当前事务,没有则抛出异常
PROPAGATION_REQUIRES_NEW 新建事务,如果有事务,则挂起当前事务
PROPAGATION_NOT_SUPPORTED 非事务方式运行,如果有事务,则挂起当前事务
PROPAGATION_NEVER 非事务方式运行,如果有事务,则抛出异常
PROPAGATION_NESTED 如果有事务,则以嵌套方式运行<br>没有则与PROPAGATION_REQUIRED类似
2.2.2 事务隔离级别

Spring事务隔离级别

隔离级别 解释
ISOLATION_DEFAULT 使用数据库默认隔离级别(默认)
ISOLATION_READ_UNCOMMITTED 允许读取尚未提交的更改。有脏读、不可重复读、幻读
ISOLATION_READ_COMMITTED 允许读取已提交的更改。无脏读,有不可重复读、幻读
ISOLATION_REPEATABLE_READ 事务中多次读取同一数据始终一致。无脏读、不可重复读,有幻读
ISOLATION_SERIALIZABLE 所有事务依次排队执行。无脏读、不可重复读、幻读

脏读、不可重复读、幻读

隔离级别 脏读 不可重复读 幻读
READ_UNCOMMITTED 允许 允许 允许
READ_COMMITTED 禁止 允许 允许
REPEATABLE_READ 禁止 禁止 允许
SERIALIZABLE 禁止 禁止 禁止
2.2.3 事务超时时间

事务超时时间,默认为-1。专门为PROPAGATION_REQUIREDPROPAGATION_REQUIRES_NEW设计,因为它仅适用于新启动的事务。

2.2.4 事务是否只读

是否优化为只读事务,默认为false

2.3 事务状态(TransactionStatus)

一个业务操作可能会开启多个事务。要想标注每个事务的具体状态,可以使用TransactionStatus实例来描述。

3 事务管理的方式

Spring提供了两种事务管理方式:编程式事务管理,声明式事务管理。

  • 编程式事务管理:使用TransactionTemplate来简化编程式事务和异常处理。
  • 声明式事务管理:基于AOP实现。对方法前后进行拦截,在方法开始前创建或加入一个事务,执行后根据执行情况提交或回滚事务。

声明式事务管理优于编程式事务管理,主要是无侵入,低耦合。声明式事务不足之处在于,事务控制粒度只能是方法级,无法像编程式事务那样可以做到代码块级别。

以下只讲下Transactional注解方式的事务管理。

3.1 Transactional注解

public @interface Transactional {
  
  // 事务管理器
  @AliasFor("transactionManager")
	String value() default "";
  @AliasFor("value")
	String transactionManager() default "";
  
  // 事务传播方式 默认`REQUIRED`
  Propagation propagation() default Propagation.REQUIRED;
  
  // 事务隔离级别 默认`DEFAULT`
  Isolation isolation() default Isolation.DEFAULT;
  
  // 事务超时时间 默认-1不超时;设置后,超时则自动回滚
  int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
  
  // 是否只读
  boolean readOnly() default false;
  
  // 指定回滚/不回滚异常 默认`RuntimeException`异常时回滚
  Class<? extends Throwable>[] rollbackFor() default {};
  String[] rollbackForClassName() default {};
  Class<? extends Throwable>[] noRollbackFor() default {};
  String[] noRollbackForClassName() default {};
}
3.1.1 常见事务失效场景
  1. 使用try...catch...将异常信息内部消化,Transactional无法感知异常。
  2. private方法上添加Transactional注解无效
  3. 默认情况下,非RuntimeException不会触发异常回滚。需使用@Transactional(rollbackFor = Exception.class)指定要回滚的异常
  4. 没有Transactional注解的方法,内部调用有Transactional注解的方法事务无效。注解注入基于AOP实现。
3.1.2 关于同一类内部方法相互调用问题

在同一个类里面相互调用事务方法时,由于切面切的是发起事务的方法,所以内部无论调用什么事务方法都会被认为是this当前对象调用的普通方法。

事务是根据动态代理生成的动态对象去执行事务的控制,所以同类方法内部调用其他事务方法必须拿到其对应的代理对象去调用才生效,或者放置到其他类里面。

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部