1、什么是事务
事务(Transaction)指一个操作,由多个步骤组成,要么全部成功,要么全部失败。比如我们常用的转账功能,假设A账户向B账号转账,那么涉及两个操作:
(1)从A账户扣钱;
(2)往B账户加入等量的钱。
因为是独立的两个操作,所以可能有一个成功,一个失败的情况。但是因为在这种场景下,必须要保证事务,即要么同时成功,要么同时失败(一个失败需要回滚),不能存在从 A 账户扣钱成功,往 B 账户加入等量钱失败这种情况。
2、数据库事务四个特性
数据库事务具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为 ACID 特性。原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行,多个并发事务之间要相互隔离。
持久性(Durability):一个事务一旦提交,他对数据库的修改应该永久保存在数据库中。
介绍完事务四大特性(ACID)后,重点要讲事务的隔离性(Isolation)。
3、事务隔离
3.1一个事务怎么会干扰到其他事务?
举个例子,假设有InnoDB表:t(id PK, name);,
表中有三条数据:
1 小红
2 小明
3 小王
开启两个事务A,事务B。
脏读:读取到读未提交的数据,事务A更新数据未提交,事务B读取数据,事务A提交,未提交的数据就是脏读,脏数据
不可重复读:B事务读取了两次数据,在这两次的读取过程中A事务修改了数据,B事务的这两次读取出来的数据不一样。已提交事务A对事务B产生的影响,这个影响叫做“不可重复读”(Nonrepeatable Read)
幻读:B事务读取了两次数据,在这两次的读取过程中A事务添加了数据,B事务的这两次读取出来的集合不一样。这次是已提交事务A对事务B产生的影响,这个影响叫做“幻读”。幻读流程看起来和不可重复读差不多,幻读强调的是集合的增减,不是单独一条数据的修改。
脏读和不可重复读的区别:脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
不可重复读和幻读的异同:都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如增删数据)。
除了以上还存在一种更新丢失的问题:
1、更新丢失(Lostupdate)
两个事务同时更新,第二个事务回滚会覆盖第一个事务更新的数据,导致更新丢失
2、两次更新问题(Secondlost updates problem)
两个事务都读取了数据,并同时更新,第一个事务更新失败,因为被第二个事务覆盖。
可以看到,并发的事务可能导致其他事务:
(1)脏读;
(2)不可重复读;
(3)幻读;
(4)更新丢失
3.2事务的隔离级别
SQL92标准定义了四种隔离级别:
(1)读未提交(Read Uncommitted);解决更新丢失
(2)读提交(Read Committed, RC);解决脏读和更新丢失
(3)可重复读(Repeated Read, RR);解决不可重复读,脏读和更新丢失
(4)串行化(Serializable);顺序执行,一个个来,解决所有问题
事务在各种隔离级别下,并发事务可能出现的问题:
在MySQL数据库中,支持上面四种隔离级别,默认级别为Repeatable read (可重复读);在RR级别下,InnoDB通过加锁方法解决了幻读问题。下篇文章更新mysql锁机制会细谈。