mysql锁

1. 相关概念

按锁的粒度分: 表锁、页锁、行锁

行锁是锁表粒度最小、最细的一种锁,能大大减少数据库冲突的概率,当然锁表的开锁也是最大的
表锁是粒度最大的一种锁,是对整张表进行加锁,是对整张表进行加锁,不会出现死锁的情况,但锁冲突的概率较大,常用的InnoDB引擎支持行锁和表锁
页级锁是粒度介于行锁和表锁之间,BDB引擎支持页锁

行级锁按使用方式分:共享锁、排它锁

共享锁:也叫读锁,或是S锁, 数据使用共享锁后,不能对数据进行修改,其它事务也只能使用共享锁,而不能使用排它锁
排它锁:也叫写锁、独占锁,或是X锁,使用排它锁的事务,可以读也可以写,其它事务不能使用共享锁或是排它锁

行级锁按类型分:记录锁、间隔锁、临键锁、插入意向锁

记录锁Record Lock,锁住特定的记录,当然如果没有查询到记录时,就会上升到表锁
间隔锁Gap Lock,就是在索引的间隙上加上锁,这里是实现防止可重复读的主要原因,是一个左开右开的区间
临键锁Next-key Lock,就是记录锁+间隔锁,是一个左开右闭的区间
插入意向锁Insert Intention Lock,是一种间隔锁,会和间隔锁及临键锁发生冲突,以阻止其他插入操作执行,以提高并发插入的性能

聚簇索引、非聚簇索引

聚簇索引:查找的数据就在索引中,比如主键,或第一个唯一键,或数据库内部维护的行ID
非聚簇索引:查找的数据不在索引中,一般为普通二级索引,真实数据还需要从聚簇索引中获取

2. 与锁相关的参数

锁等待的时间
mysql> SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50    |
+--------------------------+-------+
1 row in set (0.00 sec)

缺省为50秒,

mysql> set innodb_lock_wait_timeout=5;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 5     |
+--------------------------+-------+
1 row in set (0.00 sec)

这里我们将缺省时间调整了5秒

当前是否有锁表
mysql> show OPEN TABLES where In_use > 0;
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| my_order | goods |      1 |           0 |
+----------+-------+--------+-------------+
1 row in set (0.00 sec)

这里我们可以看,goods被锁住了

当前正在锁的表
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
+-------------------+-------------+-----------+-----------+--------------------+------------+------------+-----------+----------+-----------+
| lock_id           | lock_trx_id | lock_mode | lock_type | lock_table         | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-------------------+-------------+-----------+-----------+--------------------+------------+------------+-----------+----------+-----------+
| 196181479:385:3:2 | 196181479   | X         | RECORD    | `my_order`.`goods` | PRIMARY    |        385 |         3 |        2 | 1         |
| 196181478:385:3:2 | 196181478   | X         | RECORD    | `my_order`.`goods` | PRIMARY    |        385 |         3 |        2 | 1         |
+-------------------+-------------+-----------+-----------+--------------------+------------+------------+-----------+----------+-----------+
2 rows in set (0.00 sec)

可以看出,goods表有两条锁记录,模式是排他锁,是记录锁

等待锁的表
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
+-------------------+-------------------+-----------------+-------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id  |
+-------------------+-------------------+-----------------+-------------------+
| 196181479         | 196181479:385:3:2 | 196181478       | 196181478:385:3:2 |
+-------------------+-------------------+-----------------+-------------------+
1 row in set (0.00 sec)

这个表可以看到一条记录,一个是当前请求事务ID,还是阻塞中的事务ID

查看详细的运行时信息
mysql> show engine innodb status\G;
LOCK WAIT 2 lock struct(s), heap size 1184, 1 row lock(s)
MySQL thread id 4926, OS thread handle 0x6318, query id 1728630 localhost ::1 root statistics
select * from goods where id=1 for update
------- TRX HAS BEEN WAITING 2 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 385 page no 3 n bits 80 index `PRIMARY` of table `my_order`.`goods` trx id 196181479 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 8; compact format; info bits 0

上面是截取了一小段,这里可以看出锁表的语句

超时相关的参数
mysql> show variables like '%timeout%';
+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| connect_timeout             | 10       |
| delayed_insert_timeout      | 300      |
| innodb_flush_log_at_timeout | 1        |
| innodb_lock_wait_timeout    | 30       |
| innodb_rollback_on_timeout  | OFF      |
| interactive_timeout         | 28800    |
| lock_wait_timeout           | 31536000 |
| net_read_timeout            | 30       |
| net_write_timeout           | 60       |
| rpl_stop_slave_timeout      | 31536000 |
| slave_net_timeout           | 3600     |
| wait_timeout                | 28800    |
+-----------------------------+----------+
12 rows in set (0.00 sec)

超时相关的参数,包括前面的innodb,锁超时时间

3. 示例

间隔锁示例

1)初始表中数据


初始表数据.png

id为主键索引,num为非唯一索引
2)事务1锁表

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from goods where num=5 for update;
+----+-----------+------+---------------------+---------------------+---------------+
| id | name      | num  | ctime               | utime               | desc          |
+----+-----------+------+---------------------+---------------------+---------------+
|  3 | 小米汽车3 |    5 | 2022-01-30 22:14:49 | 2022-01-30 22:14:49 | 添加小米汽车3 |
|  4 | 小米汽车3 |    5 | 2022-01-30 22:20:36 | 2022-01-30 22:20:36 | 添加小米汽车3 |
|  5 | 小米汽车3 |    5 | 2022-01-30 22:38:49 | 2022-01-30 22:38:49 | 添加小米汽车3 |
+----+-----------+------+---------------------+---------------------+---------------+
3 rows in set (0.00 sec)

这里语句是对num=5进行锁定,因为缺省是可重复读隔离级别,实际这里是间隔锁,一个是<5,还有一个是(5,31)共两段
3)事务2插入num=2记录

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into goods(name,num) values('mi',2);
Query OK, 1 row affected (29.77 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

事务2在插入num=2时,会进入阻塞等待状态,等待事务1提交
4)事务1提交

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from goods;
+----+-----------+------+---------------------+---------------------+----------------+
| id | name      | num  | ctime               | utime               | desc           |
+----+-----------+------+---------------------+---------------------+----------------+
|  1 | 小米汽车  |   31 | 2022-01-29 10:51:32 | 2022-01-30 22:38:49 | addNum方法更新 |
|  3 | 小米汽车3 |    5 | 2022-01-30 22:14:49 | 2022-01-30 22:14:49 | 添加小米汽车3  |
|  4 | 小米汽车3 |    5 | 2022-01-30 22:20:36 | 2022-01-30 22:20:36 | 添加小米汽车3  |
|  5 | 小米汽车3 |    5 | 2022-01-30 22:38:49 | 2022-01-30 22:38:49 | 添加小米汽车3  |
|  6 | mi        |    2 | 2022-02-07 16:34:15 | 2022-02-07 16:34:15 | NULL           |
+----+-----------+------+---------------------+---------------------+----------------+
5 rows in set (0.00 sec)

事务1进行提交,事务2再提交后,再查询一下,看到了刚插入的num=2的记录。
举手之劳,不要吝惜您的赞!-_-

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容