TCL:事务控制语言,负责处理 ACID 事务,支持 commit、rollback 指令
事务的属性:原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)
隔离级别:读未提交 read uncommitted、读已经提交 read committed、可以重复读 repeatable read、可串行化 serializable

概述


  • InnoDB 引擎,支持事务
  • 事务:若干条语句组成,一系列操作
  • 关系型数据库中支持事务,必须支持其四个属性: ACID
特性 描述
原子性(atomicity) 一个事务是一个不可分割的工作单位,事务中包括的所有操作要么全部做完,要么什么都不做
一致性(consistency) 事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的,多个事务并行执行和串行执行的结果一致,也就是说结果是可预期的
隔离性(isolation) 一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰隔离性就是在一个事务处理期间,其他事务能不能访问的问题
持久性(durability) 持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响(即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态)
  1. automicity: all changes to the data must be performed successfully or not at all
  2. consistency: data must be in a consistent state before and after the transaction
  3. isolation: no other process can change the data while the transaction is running
  4. durability: the changes made by a transaction must persist

MySQL 隔离级别


引起的问题

隔离性不好,事务的操作就会互相影响,带来不同严重程度的后果。
隔离性不好会带来如下几个方面的问题:

  1. 更新丢失 Lost Update
    提交或者回滚一个事务,把其它事务已提交的更新的数据覆盖了
    事务 A 和 B,更新同一个数据,B 的更新覆盖了 A 的更新,A的更新就丢失了
  2. 脏读 Ditry Read(Uncommitted Data)
    一个事务读到另一个事务未提交的更新数据
    事务 A 和 B,事务 B 读取到了事务 A 未提交的数据(这个数据可能是一个中间值,也可能事务 A 后来回滚事务)。事务 A 是否最后提交并不关心。只要读取到了这个被修改的数据就是脏读
  3. 不可重复读 Unrepeatable read
    一个事务两次读同一行数据,可是这两次读到的数据不一样
    事务 A 在事务执行中相同查询语句,得到了不同的结果,不能保证同一条查询语句重复读相同的结果就是不可以重复读。例如,事务 A 查询了一次后,事务 B 修改了数据,事务 A 又查询了一次,发现数据不一致了
  4. 幻读 Phantom read
    一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行
    事务 A 中同一个查询要进行多次,事务 B 插入数据,导致 A 返回不同的结果集,就是幻读。数据集有记录增加/减少了,可以看做是增加/减少了记录的不可重复读

数据库隔离级别

如下,隔离级别由高到低:

隔离级别 描述
READ UNCOMMITTED 读取到未提交的数据
READ COMMITTED 读已经提交的数据,ORACLE 默认隔离级别
REPEATABLE READ 可以重复读,MySQL 的默认隔离级别
SERIALIZABLE 可串行化。事务间完全隔离,事务不能并发,只能串行执行
  • 读未提交 read uncommitted:能够读到别的事务还没提交的数据。完全没有隔离性,会出现脏读,当然还会出现更新丢失,不可重读读,幻读问题出现
  • 读已经提交 read committed:能够读取到其他事务已经提交(commit)的数据,解决了脏读。但不能解决不可重复读和幻读的问题,因为其他事务前后修改了数据或者增删了数据
  • 可以重复读 repeatable read:事务中同一条查询语句返回同样的结果,即可以重复读数据。
    • 可以重复读的实现方案:1. 对 select 数据加锁,不允许其他事务删除、修改操作;2. 第一次 select 时对最后一次确切提交的事务做快照
    • 可以重复读解决了不可以重复读问题,但可能会出现幻读,因为其他事务可以增删数据
  • 可串行化 serializable:事务串行执行。解决了更新丢失、脏读、不可重复读、幻读所有问题,但执行效率低
  • 隔离级别越高,串行化越高,数据库执行效率低;隔离级别越低,并行度越高,性能越高;隔离级别越高,当前事务处理的中间结果对其它事务不可见程度越高

数据库设置隔离级别

-- 设置会话级或者全局隔离级别,一般用会话级
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL
{READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

-- 查询隔离级别
SELECT @@global.tx_isolation;
SELECT @@tx_isolation;

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 禁用自动提交
SET AUTOCOMMIT = 0
  • START TRANSACTIONBEGIN开始一个事务
  • 使用COMMIT提交事务后,变更成为永久变更
  • ROLLBACK可以在提交事务之前,回滚变更,事务中的操作就如同没有发生过一样(原子性)
  • SET AUTOCOMMIT语句可以禁用或启用默认的autocommit模式,用于当前连接。SET AUTOCOMMIT = 0禁用自动提交事务。如果开启自动提交,如果有一个修改表的语句执行后,会立即把更新存储到磁盘

实验:开两个连接MariaDB的session(两个xshell连接同一虚拟机,并连接数据库操作)并设置session的隔离级别,分别在两个session执行select语句深入理解隔离级别

参考及扩展阅读