事务的隔离级别

数据库事务并发问题

假设现在有2个事务:Transactional01 和 Transactional02 并发执行

脏读(一定不允许发生)
  1. Transactional01 将某条记录的 age 字段的值从20修改为30
  2. Transactional02 读取了 Transactional01 更新后的值30
  3. Transactional01 回滚,age 字段的值恢复到了20
  4. Transactional02 读取到的 30 就是一个无效的值
不可重复读
  1. Transactional01 读取了 age 字段的值为20
  2. Transactional02 将 age 字段的值修改为30
  3. Transactional01 再次读取 age 字段的值为30,和第一次读取不一致
幻读
  1. Transactional01 读取了 student 表中的一部分数据
  2. Transactional02 向 student 表中插入了新的一行
  3. Transactional01 读取 student 表时,多出了一行


隔离级别

数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。

SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但是,并发性越弱。

  • 读未提交:允许 Transactional01 读取 Transactional02 未提交的数据
  • 读已提交:要求 Transactional01 只能读取 Transactional02 已提交的数据
  • 可重复读:确保 Transactional01 可以多次从一个字段中读取到相同的值,即 Transactional01 执行期间,禁止其它事务对这个字段进行更新
  • 串行化(用不到):确保 Transactional01 可以多次从一个表中读取到相同的行,在 Transactional01 执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但是性能十分低下


各个隔离级别解决并发问题的能力

事务的隔离级别 脏读 不可重复读 幻读
读未提交(Read uncommitted)

读已提交(Read committed)
可重复读(Repeatable read)
串行化(Serializable)


数据库产品对事务隔离级别的支持程度

事务的隔离级别 Oracle MySQL
读未提交(Read uncommitted) ×
读已提交(Read committed)
可重复读(Repeatable read) × (默认)
串行化(Serializable)


事务的传播行为

当事务方法被另一个事务调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。事务的传播行为可以由传播属性指定。




Spring定义了7种类型的事务传播行为

事务传播行为类型
描述
REQUIRED(最常用)
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。
SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行
MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常
REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起
NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER 以非事务方式执行,如果当前存在事务,则抛出异常
NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作



回到顶部