- 最近在看文件系统的一致性----日志部分源码。因为文件系统日志与数据库(支持事务)实现一致性实现----非常相似,看到此篇博文就来转转。
数据库的ACID四个基本要素:
- 原子性(Atomicity)
- 一致性 (Consistency)
- 隔离性 (Isolation)
- 持久性 (Durability)
针对隔离性遇到问题如下:
- 脏读(如有事务A和B,A读取了B未提交的数据)
- 不可重复读 (如有事务A和B,A负责读取,B负责写入,A连续读的过程中B写入了一次,A前后两次读出的数据不一样)
- 丢失更新(如有事务A和B,AB均写入数据,A写入的数据被B覆盖)
- 幻读 (如有事务A和B,A修改了表内数据的过程中,B向表内插入了一条数据,A修改完后发现数据并没有被全部修改完)
针对这以上四种问题,产生了以下四种隔离级别(其实可以算是3种,第一种并没有处理以上问题),在此处必须介绍以下实现隔离级别的两种锁模式:
- 共享锁:悲观锁,共享锁也叫S锁,是一种读锁,当一个事物获得了一条数据的共享锁,其它事务也能获得该共享锁,但不能获得排他锁,表明其它事务可读,但不可写。
- 排它锁:悲观锁,也叫X锁,是一种写锁,当一个事务对临界区加上排它锁,其他事物就不能获得该临界区的任何锁(共享锁,排他锁)。
- 总结一下就是共享锁保证大家可以一起读,但只能一个人写,总结一下就是共享锁保证大家可以一起读,但只能一个人写,排他锁保证只能一个人去处理数据,其他人不能读也不能写。
1. read uncommitted(未提交读):
- 意思是在当前隔离级别下,会读取到没有提交的数据。在这种模式下,1-4的问题均解决不了,但这种模式也不是说完全没加锁。在读取时是不会加锁的,但在更新数据时,对其加行级共享锁(其他事务不能更改,但可以读取,导致脏读),事务结束时释放。这种隔离级别未处理任何以上4个问题。
- 举例说明:
事务A读取某行记录,事务B也能对这行记录读取更新,当事务B更新记录时,事务A读取到B修改的版本,即使事务B未提交。
事务A和B不能同时更新(共享锁保证A获取共享锁时A能读取数据,B能获取共享锁能读,但是不能写)
2. read committed(提交读)
- 这种隔离级别表示读取的数据是已经提交成功的,解决了脏读问题,解决方式是给写数据加行级排他锁,这样写过程无法读取,直到事务处理完毕才释放排他锁,给读的数据加行级共享锁,这样读的时候也无法写,但是一旦读完该行就释放共享锁。这种模式下虽然处理了脏读,但是并没有处理丢失更新和不可重复读的问题。
- 举例说明:
事务A负责读,事务B负责写,A读完数据后释放共享锁,B更新数据,事务还未结束,A再读,两次得到的数据就不一样,产生不可重复读的问题。
同理,事务A获取共享锁,更新数据,然后释放共享锁,B此时获得排它锁,再更新数据,A的数据就可能被覆盖,产生更新丢失的问题。
3. reapetable read(可重复读)
- 这种级别下可以重复的读取数据,顾名思义解决了不可重复读的问题,同时也解决了丢失更新的问题。
- 解决方法: 给写的数据加行级排它锁,事务结束释放,给读的数据加行级共享锁,事务结束后释放。这种模式还没处理幻读问题!
- 举例说明:
事务A负责读,事务B负责写,A读完数据后等事务结束才释放共享锁,B更新数据,直到事务结束,A再读,两次得到数据均为A第一次读到的数据,解决不可重复读的问题。
事务A负责读,只为读取的数据加行级共享锁,B在A读过程中向表单中插入新数据,A没有处理到新插入的数据,产生幻读。
serializable(序列化)
- 实现也很简单,事务读数据则加表级共享锁,事务写数据则加表级排他锁,幻读问题也得到了解决。