事务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元。
- T2扣除100元,剩余0元
- T1读取到当前为0元
- T2发现操作有误,进行了rollback
- T1增加100,进行commit,最终剩余金额为100
正常逻辑下剩余金额应为200元。发生错误的原因是T1读取了T2未提交的数据,称之为脏读。
不可重复读
一个事务范围内多次查询得到了不同的值,读取了另一个事务提交的数据。 举例:事务T1, T2,T1 要给uid为123的账户增加100元,T2要给uid为123的账户扣除100元。
- T2扣除100元,剩余0元
- T1读取到当前为100元
- T2进行commit
- T1再次读取,当前金额变为0元
- T1增加100,进行commit,最终剩余金额为100
第2步和第4步查询的都是uid为123的账户,但得到的金额不同,这种情况就是不可重复读。
幻读
事务中的同一个查询,不同时间返回了不同的结果。例如一个SELECT语句执行了两次,第二次返回了两行数据, 而第一次只有一行。
举例:
mysql> SELECT * FROM account;
+-----+-------+
| uid | money |
+-----+-------+
| 123 | 100 |
+-----+-------+
事务T1,T2
- T1 查询
SELECT * FROM account WHERE money>=100;,只返回了1行数据 - T2 执行了
INSERT INTO account (uid, money) VALUES (456, 100);,并commit - T1 再次查询
SELECT * FROM account WHERE money>=100;,返回了两行数据
T1在第1步、第3步执行了相同查询,得到了不同条目的结果,此种情况称之为幻读
事务隔离级别
Read Uncommitted
读未提交,顾名思义,可以读取到其他事物已修改但未提交的数据,可导致脏读、幻读、不可重复读。
Read Committed
读已提交,可以读取其他事务中提交的数据,但不能读取其他事务中未提交的数据,所以不会发生脏读,但是会导致幻读和不可重复读
Repeatable Read
可重复读,一个事务中,多次执行查询语句,得到的结果是一样的,如SELECT * FROM account WHERE uid=123;,每次查询得到的都是事务开始时的值。但还存在幻读问题,范围查找多次查询返回条目数可能不同。
Serializable
序列化,强制所有事物排序执行,可解决脏读、幻读、不可重复读的问题,但是执行效率非常低,适用场景很少。
| 事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| Read Uncommitted | yes | yes | yes |
| Read Committed | no | yes | yes |
| Repeatable Read | no | no | yes |
| Serializable | no | no | no |
MySQL的Innodb引擎支持事务的四种隔离级别,默认为Repeatable Read,可以解决脏读、不可重复读问题,并且极大程度上避免幻读问题,详细的可继续学习MySQL MVCC