InnoDB 锁机制
数据读写可能存在的问题
如果事情能顺顺利利的按照我们预想的那样进行下去,世界将会多么美好。
- 脏读: 在一个事务A中读取到另一个事务B未提交的数据,事务B提交后A再读数据又不一样了
- 不可重复读: 针对同一条数据,两次查询的结果不一致(update & delete)
- 幻读:两次读出来的数据数量不一致(insert)
脏读和不可重复读的区别在于:脏读能读到未提交的数据,不可重复读读到了事务前后的数据,两者的表现都是针对同一条数据,读多次数据不一致。
不可重复读和幻读都是从数据一致性角度来看的,至于将数据修改操作和数据插入操作跟为两种情况是因为解决这两种情况的手段不一样,下面会分析;
锁种类
大类别上可以分为:
- 表锁
- 行锁:
从IO角度可以分为
- 读锁
- 写锁
表锁会锁住整个表的资源,性能很差,一般DDL操作会使用;大部分情况下对数据的操作都是行锁,行锁比较复杂,但是锁住的数据少,对并发影响小,性能好,接下来主要讨论行锁。行锁简单点可以分为:
- 共享锁(读锁):共享锁不会影响其他的读操作;
- 排他锁(写锁):数据一旦有修改操作,锁会升级为排他锁,这时候其他事务不能读,也不能修改这条数据;需要注意的是,当一个修改语句个where条件中没有索引列时,这个锁会变为表锁;
封锁协议
一阶段锁协议
只开启排他锁不开启共享锁,排他锁在事务结束后释放
可以保证修改不丢失,会发生脏读,因为没有共享锁,所以对于另外的事务而言,排他锁不会影响到读操作;
二阶段锁协议
在一阶段基础上开启共享锁,共享锁在读完数据后就释放而不是事务结束后释
保证修改不丢失的同时避免脏读,因为有共享锁,阻止自己读取到其他事务中正在修改的数据,从而避免脏读;此时因为读完数据就释放,之后如果再有其他事务再一次对数据进行了修改并提交,在本事务中read就会出现不可重复读现象;
三阶段锁协议
在二阶段基础上,共享锁在事务结束后释放而不是读取完后就释放
这个阶段的手段是阻止后续的事务修改数据,因为本事务在结束之前一直持有共享锁,其他事务是获取不到排他锁的,从而实现可重复读;
四阶段锁协议
这个最简单,直接加表锁,阻止其他事务所有操作,避免所有问题;
事务隔离级别
- ReadUncommited
- ReadCommited
- RepeatableRead:
- Serializable
这四种隔离级别看起来刚好跟上面的锁协议对应,但是innodb 在此基础上做了优化(MVCC);
网友评论