Mysql 共享锁、排他锁 与 事务隔离级别详解

共享锁、排他锁

InnoDB 实现了两种类型的锁机制:共享锁(S)和排他锁(X)。共享锁容许一个事务读数据,不容许修改数据,若是其余事务要再对该行加锁,只能加共享锁;排他锁是修改数据时加的锁,能够读取和修改数据,一旦一个事务对该行数据加锁,其余事务将不能再对该数据加任务锁。数据库

共享锁(S) 排它锁(X)
共享锁(S) 容许 不容许
排它锁(X) 不容许 不容许

x轴:事务A拥有的锁
y轴:事务B申请的锁微信

:一个事务在某一行数据上加上排它锁后,其余事务不能再在这行数据加任何锁,没法进行 update 与 delete,可是普通的 select 是能够的,由于普通的 select 不加任何锁,当 select .... from ... for update 时才会加上排它锁。并发

并发事务带来的问题

1.数据丢失(两个事务同时修改一行数据,其中一个事务异常回滚,致使更新失败)spa

解决办法:未提交读(Read Uncommitted):在事务 B 读取数据时,事务 A 读取数据加了共享锁,修改数据时加了排它锁。这种隔离级别,会致使脏读、不可重复读以及幻读。3d

微信截图_20200413230833.png

未提交读会致使脏读、不可重复读、幻读的缘由:尽管 A 持有排它锁,避免了两个事务同时修改的状况,可是普通的 select 不持有锁,仍是能够读到数据的,因此事务 A 屡次修改数据,事务 B 中的查询仍是能够看到的。code

2.脏读(一个事务的执行期间,另外一个事务读到了没有提交数据)blog

解决办法:已提交读(Read Committed):在事务 B 读取数据时增长了共享锁,一旦读取,当即释放锁,事务 A 读取修改数据时增长了行级排他锁,直到事务结束才释放锁。
也就是说,事务 B 在读取数据时,事务 A 只能读取数据,不能修改。当事务 B 读取到数据后,事务 A 才能修改。
这种隔离级别,能够避免脏读,但依然存在不可重复读以及幻读的问题。事务

微信截图_20200413223229.png

已提交读会致使不可重复读、幻读的缘由:事务 B 没有提交就将锁释放,致使事务 A 能够对数据进行任意修改,修改后,事务 B 再次获取共享锁查询,查询到跟以前读取不一致的数据。rem

3.不可重复读(一个事务的执行期间,另外一个事务连续两次读取到的值不同)it

解决办法:可重复读(Repeatable Read):在事务 B 读取数据时增长了共享锁,事务结束,才释放锁,事务 A 读取修改数据时增长了行级排他锁,直到事务结束才释放锁。
也就是说,事务 B 在没有结束事务时,事务 A 只能读取数据,不能修改。当事务 B 结束事务,事务 A 才能修改。
这种隔离级别,能够避免脏读、不可重复读,但依然存在幻读的问题。

微信截图_20200413225430.png

可重复读致使幻读的缘由:可重复读是加的行级锁,而幻读是知足查询条件的前提下数据量发生变化,即发生 insert 或 delete操做。

4.幻读(一个事务的执行期间,另外一个事务连续两次读取到的数量不一样)

解决办法:可序列化(Serializable):在事务 A 读取数据时增长了共享锁,事务结束,才释放锁,事务 B 读取修改数据时增长了表级排他锁,直到事务结束才释放锁。

可序列化解决了脏读、不可重复读、幻读等问题,但隔离级别愈来愈高的同时,并发性会愈来愈低。

微信截图_20200413230447.png

小结

能够看出,控制数据库并发带来的问题依赖的是锁粒度的扩大来解决的。

可是隔离级别越大,并发性就越差,若是业务场景容许的状况下,适当减少隔离级别是处理并发的一种手段。

相关文章
相关标签/搜索