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
未提交读会致使脏读、不可重复读、幻读的缘由:尽管 A 持有排它锁,避免了两个事务同时修改的状况,可是普通的 select 不持有锁,仍是能够读到数据的,因此事务 A 屡次修改数据,事务 B 中的查询仍是能够看到的。code
2.脏读(一个事务的执行期间,另外一个事务读到了没有提交数据)blog
解决办法:已提交读(Read Committed):在事务 B 读取数据时增长了共享锁,一旦读取,当即释放锁
,事务 A 读取修改数据时增长了行级排他锁,直到事务结束才释放锁。
也就是说,事务 B 在读取数据时,事务 A 只能读取数据,不能修改。当事务 B 读取到数据后,事务 A 才能修改。
这种隔离级别,能够避免脏读,但依然存在不可重复读以及幻读的问题。事务
已提交读会致使不可重复读、幻读的缘由:事务 B 没有提交就将锁释放,致使事务 A 能够对数据进行任意修改,修改后,事务 B 再次获取共享锁查询,查询到跟以前读取不一致的数据。rem
3.不可重复读(一个事务的执行期间,另外一个事务连续两次读取到的值不同)it
解决办法:可重复读(Repeatable Read):在事务 B 读取数据时增长了共享锁,事务结束,才释放锁
,事务 A 读取修改数据时增长了行级排他锁,直到事务结束才释放锁。
也就是说,事务 B 在没有结束事务时,事务 A 只能读取数据,不能修改。当事务 B 结束事务,事务 A 才能修改。
这种隔离级别,能够避免脏读、不可重复读,但依然存在幻读的问题。
可重复读致使幻读的缘由:可重复读是加的行级锁,而幻读是知足查询条件的前提下数据量发生变化,即发生 insert 或 delete操做。
4.幻读(一个事务的执行期间,另外一个事务连续两次读取到的数量不一样)
解决办法:可序列化(Serializable):在事务 A 读取数据时增长了共享锁,事务结束,才释放锁,事务 B 读取修改数据时增长了表级排他锁
,直到事务结束才释放锁。
可序列化解决了脏读、不可重复读、幻读等问题,但隔离级别愈来愈高的同时,并发性会愈来愈低。
能够看出,控制数据库并发带来的问题依赖的是锁粒度的扩大来解决的。
可是隔离级别越大,并发性就越差,若是业务场景容许的状况下,适当减少隔离级别是处理并发的一种手段。