事务
什么是事务
所谓事务,就是一系列操作,这些操作要么都执行,要么都不执行。
事务的特性
事务必须满足ACID四大特性,原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
- 原子性:
一个事务必须被看成一个不可分割的最小单元,整个事务中的一系列操作,要么都执行,要么都不执行。
- 一致性:
一致性是在原子性基础上的补充。
数据库总是将数据从一个状态通过一系列操纵之后变成另一个状态。在一系列操纵失败的情况下必须保证数据没有发生变化,和原来的状态一致。
- 隔离性:
通常来说,一个事务所做的修改在最终提交之前,对其他事务是不可见的。但隔离有四个级别。
- 持久性:
一旦事务提交之后,该事务所做的修改就会永久的保存在数据库中。
事务的隔离级别
上面提及隔离性的时候谈到了事务的隔离级别。在实际应用中,事务分为四种隔离级别。
在介绍隔离级别之前,先举例介绍一下脏读、不可重复读和幻读。
- 脏读
当一个事务正在访问数据,并且对数据进行了修改,但是此时事务还没有提交。与此同时,另一个事务也访问了这个数据,这个时候就产生了脏数据。即为脏读。
举个例子:
现在有一张库存表,里面产品A有库存10个。现在仓库管理员铁柱和狗蛋两个人同时对产品A进行操作。
1.铁柱网速比较快,先查到产品A有10个,又存入了10个产品A,但还没有提交。
2.狗蛋网速比较慢,刚刚查到产品A,这个时候查到有20个产品A,并且准备取出20个。
3.铁柱突然回滚了刚才的操作,使得产品A的库存又变回了10。
这时,狗蛋读取的库存20就是脏数据。
- 不可重复读
多次读取,数据不一致。一个事务,多次读取同一个数据时,另一个事务访问并修改了该数据。恰好放生在第一个事务两次读取该数据之前,那么这两次读取到的数据就可能不一样,因此为不可重复读。
举个例子:
还是有一张库存表,里面产品A有库存10个。现在仓库管理员铁柱和狗蛋两个人同时对产品A进行操作。
1.铁柱先查询产品A,此时库存为10,但是铁柱有点眼花,需要再查询一遍
2.在铁柱第二遍查询之前,刚好狗蛋给产品A添加了10个库存。
3.在狗蛋添加库存之后,铁柱刚好查完第二遍,发现库存变成了20,开始怀疑自己老眼昏花了。
这时,就产生了铁柱在查询库存两次读取不一致的问题,即为不可重复读。
- 幻读
一个事务对表全部行的数据进行了修改(比如添加了一行数据),这时,另一个事务也对表全部行的数据进行了修改(比如删除了一行数据)。这就造成了表没有被修改的假象。即为幻读。
举个例子:
还是有一张库存表,现在库存表里有10个不同的产品。仓库管理员铁柱和狗蛋两个人需要对产品进行整理并统计。
1.铁柱需要添加新的产品B,在添加之前先查询了一下数据库,确认表里没有产品B,但此时铁柱还没有开始添加。
2.狗蛋也接到任务要添加产品B,但狗蛋没有铁柱做事心细直接添加了产品B,并提交了事务。
3.铁柱做事认真,又查了一遍,确认自己没有添加产品B后,开始添加产品B,结果数据库报错说已经存在了产品B。
1. READ UNCOMMITTED(未提交读)
在未提交读的隔离级别中,一个事务对数据进行了修改,即使没有提交,其他事务也会获得修改后的数据。
未提交读会存在脏读、不可重复读、幻读的可能性。
2. READ COMMITTED(提交读)
在提交读的隔离级别中,一个事务对数据进行了修改,只有提交后其他事务才会获得修改后的数据。
提交读会存在不可重复读、幻读的可能性。
3. REPEATABLE READ(可重复读)
在可重复读的隔离级别中,一个事务中的多次查询结果都是一致的,不受其他事务的影响。
可重复读存在幻读的可能性 (但MySQL的InnoDB引擎的RR隔离级别其实并不会出现幻读。)
4. SERIALIZABLE(序列化)
隔离的最好级别,它通过强制事务串行执行,避免了所谓的幻读,但是由于读取每一行数据时都进行了加锁操作,性能大大降低。
练习题
现在库存表里有iPhone 100部。
事务A:1) 开启事务 2) 扣除10部iPhone 3) 提交事务
事务B:4) 开启事务 5) 查询iPhone库存 6) 查询iPhone库存 7) 提交事务 8)查询iPhone库存
当执行顺序为 14526378 时,事务B在READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 隔离级别下三次查询的结果分为是多少?