MySQL 提供了锁机制和 MVCC 机制来保证并发操作的安全性, 这里主要讨论锁机制,
MVCC 见下篇文章
MySQL 的锁按照锁粒度可分为行锁与表锁, 按照操作类型划分可读锁和写锁
InnoDB 存储引擎支持表锁和行锁, 默认锁为行锁, MyIsam 只支持表锁
锁粒度越高则并发性越好
表锁
一, 操作语法
1, show open tables; 查看数据库中哪些表加了锁
in-use 为 0 则表示未加锁
2, lock table (table_name) read(write)
3, unlock tables; 解锁
二, 示例
1, 读锁
开了两个 MySQL 客户端, 左边客户端中给 mytest 数据库中的 test1 表加了读锁
左客户端执行读操作, 右客户端执行读操作, 可以看到两者都可以执行
对于同一数据库中的其他表操作, 左客户端拒绝执行, 右客户端可以执行
对于被锁住的表执行写操作
左客户端拒绝执行
右客户端阻塞住
此时我们解锁
可以看到右客户端立即被释放并正确执行操作
2, 写锁
给左客户端 test1 表加上写锁
左客户端读 / 写正常, 右客户端读 / 写均被阻塞
左客户端读 / 写该数据库中的其他表拒绝执行, 右客户端可以正常执行
行锁
因为 MySQL 默认的存储引擎是 InnoDB, 而 InnoDB 默认为行锁, 我们要测试行锁首先需要把 MySQL 的自动提交关闭
行级锁读操作两个客户端互不影响
写操作如果操作的不是同一行, 也不影响, 若操作的是同一行则后一个客户端的请求被阻塞, 直到前一个客户端的请求提交
注意点
1, 间隙锁
我们在左边客户端对 id 在 (0,5] 范围内的数据做写操作, 但是由于数据表中没有 id 为 4 的数据行, 按理说右边数据库插入一个 id 为 4 的数据行不会被锁住, 但是事实表明它被锁住了. 这既是 MySQL 的间隙锁机制. 因此我们在数据库操作时其实应该避免这种间隙的产生, 我们可以在表里设置一个状态位, 当要删除某一数据行时, 可以选择将该状态位设置为无效而不是真正的删除.
2, 索引失效
当 where 查询条件没有索引时, 行锁变表锁
当 where 查询条件有索引但是索引失效时, 行锁仍然变表锁
当左客户端在已经减了索引的 loc 列用 int 型来查找时, 索引失效就会导致整张表被锁住
行锁变表锁的原因: MySQL 的行锁是用索引实现的
3, 如何锁住一行
在 select 语句找出某一行之后加一个 for update
来源: https://www.cnblogs.com/huanglf714/p/10750520.html