0%

Spring事务(一)

什么是事务

  • 事务是一组逻辑上的操作,要么都执行,要么都不执行
  • 事务能否生效需要数据库引擎的支持,比如常用的 MySQL 数据库默认使用支持事务的innodb引擎。但是,如果把数据库引擎变为 myisam,那么程序也就不再支持事务了。

事务的ACID特性

  • 原子性:一个事务的操作,要么全部执行,要么全部不执行
  • 一致性:执行事务前后,数据保持一致
  • 隔离性:一个事务的执行不受其他事务的影响
  • 持久性:事务提交后对数据库的影响是永久的

并发事务的问题

  • 多个任务对同一个数据进行操作
  • 丢失修改:多个事务对同一个数据进行修改,之后的事务修改的结果覆盖了之前的。
  • 脏读:一个事务对数据的修改还没有提交,另一个事务就访问使用了这个数据。
  • 不可重复读:一个事务多次对一个数据读取,在这个中间另一个事务修改了该数据,导致,前一个前后读取的结果不一样。
  • 幻读:前一个事务读了几条记录,后一个事务插入或删除了记录,导致前一个事务再次读的时候数据多了或少了。

SQL 标准定义了四个隔离级别

  • READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • REPEATABLE-READ(可重读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

Spring对事务的支持

编程式事务管理

  • 通过TransactionTemplate和TransactionManager手动管理事务

声明式事务管理

  • 使用 @Transactional注解进行事务管理,基于AOP实现的

Spring事务管理接口

  • PlatformTransactionManager: (平台)事务管理器接口,Spring 事务策略的核心。
    • PlatformTransactionManager 会根据 TransactionDefinition 的定义比如事务超时时间、隔离级别、传播行为等来进行事务管理 ,而 TransactionStatus 接口则提供了一些方法来获取事务相应的状态比如是否新事务、是否可以回滚等等。
    • Spring 并不直接管理事务,而是提供了多种事务管理器 。Spring 事务管理器的接口是: PlatformTransactionManager 。通过这个接口,Spring 为各个平台如 JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
1
2
3
4
5
6
7
8
public interface PlatformTransactionManager {
//获得事务
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
//提交事务
void commit(TransactionStatus var1) throws TransactionException;
//回滚事务
void rollback(TransactionStatus var1) throws TransactionException;
}
  • TransactionDefinition: 事务(属性)定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。
    • 这个类就定义了一些基本的事务属性
    • 事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。
1
2
3
4
5
6
7
8
9
10
11
// 返回事务的传播行为,默认值为 REQUIRED。
int getPropagationBehavior();
//返回事务的隔离级别,默认值是 DEFAULT
int getIsolationLevel();
// 返回事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
int getTimeout();
// 返回是否为只读事务,默认值为 false
boolean isReadOnly();

@Nullable
String getName();
  • TransactionStatus: 事务运行状态
    • TransactionStatus接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息。
1
2
3
4
5
6
7
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}

TransactionDefinition接口中定义五个隔离级别

ISOLATION_DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应;

ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。

ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。

  • TransactionDefinition接口中定义了七个事务传播行为

事务传播行为:

  • 解决业务层方法之间相互调用的事务问题
  • 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

TransactionDefinition.PROPAGATION_REQUIRED

  • 使用的最多的一个事务传播行为,我们平时经常使用的@Transactional注解默认使用就是这个事务传播行为。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。也就是说:
  • 如果外部方法没有开启事务的话,Propagation.REQUIRED修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
  • 如果外部方法开启事务并且被Propagation.REQUIRED的话,所有Propagation.REQUIRED修饰的内部方法和外部方法均属于同一事务 ,只要一个方法回滚,整个事务均回滚

TransactionDefinition.PROPAGATION_REQUIRES_NEW

  • 创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。

TransactionDefinition.PROPAGATION_NESTED

  • 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
  • 也就是说:在外部方法未开启事务的情况下Propagation.NESTED和Propagation.REQUIRED作用相同,修饰的内部方法都会新开启自己的事务,且开启的事务相互独立,互不干扰。
  • 如果外部方法开启事务的话,Propagation.NESTED修饰的内部方法属于外部事务的子事务,外部主事务回滚的话,子事务也会回滚,而内部子事务可以单独回滚而不影响外部主事务和其他子事务

TransactionDefinition.PROPAGATION_MANDATORY

  • 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

TransactionDefinition.PROPAGATION_SUPPORTS

  • 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行

TransactionDefinition.PROPAGATION_NOT_SUPPORTED

  • 以非事务方式运行,如果当前存在事务,则把当前事务挂起。

TransactionDefinition.PROPAGATION_NEVER

  • 以非事务方式运行,如果当前存在事务,则抛出异常

配置事务的属性

  • isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
  • propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
  • read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
  • timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
  • rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
  • no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。

----------- 本文结束啦感谢您阅读 -----------