1、概述
不同的存储引擎支持不同的锁机制,MyISAM和MEMORY存储引擎采用的是表级锁;BDB存储引擎采用的是页面锁,也支持表级锁;InnoDB则即支持行级锁,也支持表级锁,默认是行级锁。
- 表级锁:开销小,加锁快;不会出现死锁;锁定粒度小,发生锁冲突的概率最高,并发度最低。
- 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
- 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
2、MyISAM表锁
有两种模式:表共享读锁和表独占写锁。锁模式的兼容性如下表所示:
当前\是否兼容\请求锁 | 读锁 | 写锁 |
读锁 | 是 | 否 |
写锁 | 否 | 否 |
如何加表锁:
MyISAM在执行查询语句前,会自动给涉及的所有表加读锁,在执行更新(增删改)操作前,会自动给涉及的表加写锁,不需要用户显示加锁。注意,当用户在执行LOCK TABLES后,只能访问显示加锁的这些表,不能访问未加锁的表;同时,如果加的是读锁,那么只能执行查询操作,而不能执行更新操作。
并发插入:
MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为0、1或2。
为0:不允许并发插入。
为1:当MyISAM表中没有空洞(即表的中间没有被删除的行),则允许在一个进程读表的同时,另一个进程从表尾插入记录。
为2:无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。
当session_1获得了一个表的READ LOCAL锁,该线程可以对表进行查询操作,但不能对表进行更新操作;其他线程,虽然不能对表进行删除和更新操作,但可以对该表进行并发插入操作。
3、InnoDB锁问题
背景知识:
事务及其ACID属性。原子性、一致性、隔离性和持久性。并发事务
更新丢失、脏读、不可重复读、幻读。事务隔离级别
隔离级别\读取一致性及并发副作用 读数据一致性 脏读 不可重复读 幻读 未提交读 最低级别,只能保证不读取物理上损坏的数据 是 是 是 已提交读 语句级 否 是 是 可重复读 事务级 否 否 是 可序列化 最高级别,事务级 否 否 否 4、InnoDB实现了一下两种类型的行锁:
共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
排他锁(X):允许获得排它锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
为了允许行锁和表锁共存,实现多粒度锁值,InnoDB还有两种内部使用的意向锁,都是表锁:
意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁钱必须先取得该表的IX锁。
请求锁模式\是否兼容\当前锁模式 | X | IX | S | IS |
X | 冲突 | 冲突 | 冲突 | 冲突 |
IX | 冲突 | 兼容 | 冲突 | 兼容 |
S | 冲突 | 冲突 | 兼容 | 兼容 |
IS | 冲突 | 兼容 | 兼容 | 兼容 |
相关语句:
共享锁:select * from table_name where … lock in share mode;
排他锁:select * from table_name where … for update;
注意,在使用共享锁时,如果两个事务 获得共享锁时,都需要对该记录进行更新操作,则很有可能造死锁。因此,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT…FOR UPDATE方式获得排他锁。