读未提交(Read Uncommitted)的锁机制:
在事务开始以后,遇到SQL的CRUD语句时,如果是读操作,就给该行数据一个S锁,如果是写操作,给要准备写操作的这一行数据加一个X锁。读或写完就立马释放掉锁。
在其他事务修改该行数据的时候,不让其他进程对该行数据有任何操作(不能加X和S锁)。而读该行数据的时候,其他进程不能更改,但可以读(可以加S锁但不能加X锁)。最后commit/rollback。
读未提交不能解决:脏读,不可重复读,幻读。下面是一个脏读的例子。
Transaction A | Transaction B | |
T1 | mysql> use sys; mysql> select @@TX_ISOLATION; mysql> start transaction; | mysql> use sys; mysql> select @@TX_ISOLATION; mysql> start transaction; |
T2 | mysql> select * from test; | |
T3 | mysql> update test set price = 110 where id = 1; | |
T4 | mysql> select * from test; 【说明】出现脏读 | |
T5 | mysql> rollback; | |
T6 | mysql> select * from test; mysql> rollback; |
读提交(Read committed)的锁机制:
读未提交会出现脏读。只需调整锁的位置。之前是只要写操作完该数据就立马释放掉X锁,现在是把释放X锁的位置调整到事务提交之后。此时在事务提交前,其他进程是无法对该行数据进行读取和修改的。
既然说此种隔离性是在事务提交后才释放锁,但是你会发现有些数据库,在试验过程中,在该数据未提交前,另一个事务也是仍然可以读取的。原因就是它们使用了一个并发版本控制机制(MVCC)。为了提高系统的并发量,在事务未提交前,虽然事务内操作的数据是锁定状态,但是另一个事务仍然可以读取(但不能修改)。比如对于数据项A,它的数据版本为A1->A2->A3,最新版本是A3。如果事务T1在读写数据项A时,A1和A2已提交的,事务T2正在修改A3,那么A3可以被提交,也可能被回滚。在使用锁协议时,事务X要等待Y结束,才能判断是否读到A3。在MVCC中,事务X可以读取已经提交的A2,而不必等待A3。这么操作逻辑上是合理的,因为事务T1读到了一个最新的已经提交数据,这不会带来数据不一致,也避免了读写操作的冲突等待。在上面的情况中,X可以读到A2,如果X要写A怎么办?从逻辑上说,A3不确定是提交还是回滚,X必须等待Y结束,才能开始写操作。
读提交解决了脏读问题,但是不能解决:不可重复读,幻读。下面是几个例子,分别验证了读提交避免了脏读,但是出现了不可重复读,以及MVCC中可以读到前一个版本的快照和不能同时写的操作。
重复读(Repeatable Read)的锁机制:
理想的工业标准是,在读提交的基础上继续调整锁的位置,之前是只要读操作完该数据就立马释放掉S锁,现在将其调整到事务结束后再释放S锁。即在读的时候不允许其他事务修改这条记录。
MySQL默认为这个隔离级别,可以防止脏读,不可重复读,但是不能防止幻读。
但是,在MVCC机制下,为了使这种隔离级别的性能提高,MySQL InnoDB在重复读(Repeatable Read)的锁机制上也做了相应的处理。
具体请看下节内容:
序列化(Serializable):
不再赘述。在该级别下,事务顺序串行执行,不仅可以避免脏读、不可重复读,还避免了幻像读。
转载于:https://www.cnblogs.com/storml/p/7839055.html