数据库事务

155 阅读4分钟

事务ACID

ACID指在可靠数据库管理系统中,事务(transation)应该具有的四个特性:原子性、一致性、隔离性和持久性

  • 原子性(Atomicity):一个事务里面对数据库的操作,要么全都提交成功,要么全部失败回滚
  • 一致性(Consistent):事务必须使数据库从一个正确的状态变换到另一个正确的状态
  • 隔离性(Isolation):多个连接并发访问数据库时,多个事务之间要隔离,不能互相干扰
  • 持久性(Durability):一个事务一旦提交了,对数据库中的数据改变是永久的,即使数据库遇到故障的情况也不会丢失已提交的事务

关于一致性,可以理解为通过原子性、隔离性、持久性来达到一致性。

四种事务隔离级别

四种事务隔离级别分别是读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)、串行化(Serializable)。 不同的隔离级别会产生不同的问题,包括脏读、幻读、不可重复读。

脏读、幻读、不可重复读

脏读

一个事务可以读取到另一个事务未提交的数据,另一事务回滚,第一个事务就读取到了脏数据

mysql> SELECT * FROM account;
+-----+-------+
| uid | money |
+-----+-------+
| 123 |   100 |
+-----+-------+

举例:事务T1, T2,T1 要给uid为123的账户增加100元,T2要给uid为123的账户扣除100元。

  1. T2扣除100元,剩余0元
  2. T1读取到当前为0元
  3. T2发现操作有误,进行了rollback
  4. T1增加100,进行commit,最终剩余金额为100

正常逻辑下剩余金额应为200元。发生错误的原因是T1读取了T2未提交的数据,称之为脏读。

不可重复读

一个事务范围内多次查询得到了不同的值,读取了另一个事务提交的数据。 举例:事务T1, T2,T1 要给uid为123的账户增加100元,T2要给uid为123的账户扣除100元。

  1. T2扣除100元,剩余0元
  2. T1读取到当前为100元
  3. T2进行commit
  4. T1再次读取,当前金额变为0元
  5. T1增加100,进行commit,最终剩余金额为100

第2步和第4步查询的都是uid为123的账户,但得到的金额不同,这种情况就是不可重复读。

幻读

事务中的同一个查询,不同时间返回了不同的结果。例如一个SELECT语句执行了两次,第二次返回了两行数据, 而第一次只有一行。

举例:

mysql> SELECT * FROM account;
+-----+-------+
| uid | money |
+-----+-------+
| 123 |   100 |
+-----+-------+

事务T1,T2

  1. T1 查询 SELECT * FROM account WHERE money>=100;,只返回了1行数据
  2. T2 执行了 INSERT INTO account (uid, money) VALUES (456, 100);,并commit
  3. T1 再次查询 SELECT * FROM account WHERE money>=100;,返回了两行数据

T1在第1步、第3步执行了相同查询,得到了不同条目的结果,此种情况称之为幻读

事务隔离级别

Read Uncommitted

读未提交,顾名思义,可以读取到其他事物已修改但未提交的数据,可导致脏读、幻读、不可重复读。

Read Committed

读已提交,可以读取其他事务中提交的数据,但不能读取其他事务中未提交的数据,所以不会发生脏读,但是会导致幻读和不可重复读

Repeatable Read

可重复读,一个事务中,多次执行查询语句,得到的结果是一样的,如SELECT * FROM account WHERE uid=123;,每次查询得到的都是事务开始时的值。但还存在幻读问题,范围查找多次查询返回条目数可能不同。

Serializable

序列化,强制所有事物排序执行,可解决脏读、幻读、不可重复读的问题,但是执行效率非常低,适用场景很少。

事务隔离级别脏读不可重复读幻读
Read Uncommittedyesyesyes
Read Committednoyesyes
Repeatable Readnonoyes
Serializablenonono

MySQL的Innodb引擎支持事务的四种隔离级别,默认为Repeatable Read,可以解决脏读、不可重复读问题,并且极大程度上避免幻读问题,详细的可继续学习MySQL MVCC