mysql
默认的,会存在幻读;
serializable
级别可以解决所有的数据库并发问题,但是它会在读取的每一行数据上都加锁,这就可能导致大量的超时和锁竞争问题,从而导致效率下降 。所以我们在实际应用中也很少使用serializable
,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别 。锁为什么要加锁如果有多个并发请求存取数据,在数据就可能会产生多个事务同时操作同一行数据 。
也就是我们上面说到的在并发情况下会发生的这些问题,
如果并发操作不加控制,不加锁的话,就可能写入了不正确的数据,或者导致读取了不正确的数据,破坏了数据的一致性 。因此需要考虑加锁
InnoDB的七种锁共享/排他锁InnoDB呢实现了两种标准的行级锁:共享锁(简称S锁)、排他锁(简称X锁) 。
- 共享锁:简称为S锁,在事务要读取一条记录时,需要先获取该记录的S锁 。
- 排他锁:简称X锁,在事务需要改动一条记录时,需要先获取该记录的X锁 。
T1
持有行R的S
锁,那么另一个事务T2
请求访问这条记录时,会做如下处理:- T2 请求
S
锁立即被允许,结果T1和T2
都持有R行的S
锁 - T2 请求
X
锁不能被立即允许,此操作会阻塞
T1
持有行R的X
锁,那么T2
请求R的X、S
锁都不能被立即允许,T2
必须等待T1
释放X
锁才可以,因为X
锁与任何的锁都不兼容 。兼容性 SX S兼容不兼容 X 不兼容 不兼容意向锁意向锁是一种不与行级锁冲突的表级锁 。未来的某个时刻,事务可能要加共享或者排它锁时,先提前声明一个意向 。注意一下,意向锁,是一个表级别的锁 。
因为InnoDB是支持表锁和行锁共存的,如果一个事务A获取到某一行的排他锁,并未提交,这时候事务B请求获取同一个表的表共享锁 。因为共享锁和排他锁是互斥的,因此事务B想对这个表加共享锁时,需要保证没有其他事务持有这个表的表排他锁,同时还要保证没有其他事务持有表中任意一行的排他锁 。
然后问题来了,你要保证没有其他事务持有表中任意一行的排他锁的话,去遍历每一行?这样显然是一个效率很差的做法 。为了解决这个问题,InnoDB提出了意向锁 。
如果一个事务A获取到某一行的排他锁,并未提交,这时候表上就有
意向排他锁
和这一行的排他锁
。这时候事务B想要获取这个表的共享锁,此时因为检测到事务A持有了表的意向排他锁
,因此事务A必然持有某些行的排他锁,也就是说事务B对表的加锁请求需要阻塞等待,不再需要去检测表的每一行数据是否存在排他锁啦 。这样效率就高很多啦 。记录锁记录锁是最简单的行锁,仅仅锁住一行 。如:
SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE
,如果c1字段是主键或者是唯一索引的话,这个SQL会加一个记录锁(Record Lock)记录锁永远都是加在索引上的,即使一个表没有索引,InnoDB也会隐式的创建一个索引,并使用这个索引实施记录锁 。它会阻塞其他事务对这行记录的插入、更新、删除 。
经验总结扩展阅读
- 抽烟会引起胸闷气短吗
- 关于兔子的恐怖故事
- 关于山高的比喻句
- 关于安逸的格言
- 关于受的四字词语
- 关于少林寺的动画片有哪些
- 关于蜂巢素的问题
- 生活中关于诚信的例子有哪些
- 引擎之旅 Chapter.4 日志系统
- 到寺庙烧香有什么讲究