Mysql 死锁过程及案例详解之用户自定义锁
Posted ShenLiang2025
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql 死锁过程及案例详解之用户自定义锁相关的知识,希望对你有一定的参考价值。
mysql 用户自定义锁介绍
锁简介
当多个请求连接到数据库时,能保证同类查询执行时不相互冲突的机制即是锁。比如马路上的信号灯就是一个解决冲突的例子,在一定的时间内锁定了能通行的方向或者路线。MySQL里的锁实际上是一个处于处于授予或挂起状态锁请求。
锁的访问级别
锁的访问级别(Lock Access Levels)即定义锁以那种方式进入(使用)。主要有两种方式:共享的(shared)和排他的(exclusive)。
共享锁是比较宽松的锁,即允许多个连接访问。而排他锁则只能指定一个连接访问的锁。有时我们又称共享锁为读锁,排他锁为写锁。
锁的粒度
Mysql通过各种锁的粒度(类型)去控制数据的访问,这样可以尽可能的进行数据的并发访问。
用户自定义锁User-Level Locks
用户自定义锁是一种显式的锁,即用户通过数据库内置的函数生成锁。这些锁都是排他锁且可以指定的锁名最多64个字符。
函数名 | 功能 | 参数 | 额外说明 |
GET_LOCK | 按照指定的名称、等待时间获得(生成)锁。 | 1 name 锁名 2 timeout 锁等待时间 | 1 timeout为正数时,如果在指定timeout连接上锁则返回1,否则返回0。 2 timeout为负数时会一直等待锁。 |
IS_FREE_LOCK | 检查指定的锁是否可用 | name 名字 | 可用返回1否则为0 |
IS_USED_LOCK | 检查指定的锁是否已用 | name 名字 | 如果锁可用时返回连接ID(connection id),不可用时返回NULL。 |
RELEASE_ALL_LOCKS | 释放用户锁 | 返回锁的数量。 | |
RELEASE_LOCK | 释放指定的用户锁 | name锁名 | 1 锁存在:释放成功返回1,否则为0(锁存在但不属于该连接时)。 2 锁不存在:返回null。 |
示意案例1
Step1:在第一个会话(session1)里执行:
SELECT GET_LOCK('lock_1',10);
/*此时返回为:
1
-- 即可以生成锁lock_1。
*/
Step2:此时在会话1里我们查看下锁的状态:
SELECT IS_USED_LOCK('lock_1') AS ISUsedLock,
IS_FREE_LOCK('lock_1') AS ISFreeLock
/*返回结果
ISUsedLock ISFreeLock
10 0
*/
Step3:而在另外个会话(session2)里执行:
SELECT GET_LOCK('lock_1',10);
即会话2里经过了10秒的尝试并不能获得锁lock_1。
Step4:如果在会话1里释放锁lock_1,那么会话2可以获得锁lock_1。
-- 会话1里释放锁lock_1。
SELECT RELEASE_LOCK('lock_1')
/*返回结果
RELEASE_LOCK('lock_1')
1
*/
-- 会话2里获得锁lock_1。
SELECT GET_LOCK('lock_1',10);
/*返回结果
GET_LOCK('lock_1',10)
1
*/
注:用户自定义锁是应用程序级别的锁,拿到锁的应用程序有排他性,并不针对特定的表和字段。
2 如果timeout设置为-1,那么在如上的实验中会话2会一直等待,直至会话1释放锁。
示意案例2
-- Step1:在第一个会话(session1)里执行:
SELECT GET_LOCK('lock_1',-1);
-- Step2:在第二个会话(session2)里执行:
SELECT GET_LOCK('lock_2',-1);
-- Step3:在第二个会话(session2)里执行:
SELECT GET_LOCK('lock_1',-1);
-- Step4:在第一个会话(session1)里执行:
SELECT GET_LOCK('lock_2',-1);
解释:这里我们可以看到在会话1、会话2里分别生成锁lock_1、lock_2。接下来会话2去获取lock_1,这里是无限等待(timeout为-1)。然后在会话1又获取锁lock_2,此时就发生了死锁,因为会话2的连接当前还在尝试获取锁lock_1,无法释放lock_2,此时会话1访问锁lock_2就发生死锁。当一个连接处理多个锁时会出现死锁的情况。
后续处理:分别在会话1、会话2里执行释放锁语句或者关闭连接自动释放锁。
这好比食堂里有两个人A、B都在用勺子1、2一个汤池里盛汤,但B在拿着勺2的情况下去等勺1,而A也想用B手里的勺2。这样显然会出现“冲突”,即如果双方都不谦让岂不是一直僵直在哪里了?!这就是死锁。
而对于其他分别在A、B后面排队的人,他们可能不知道A、B的状态,他们会一直等待A、B释放手中的勺子。
SELECT RELEASE_ALL_LOCKS()
自定义锁详情
通过数据字典查看用户自定义锁详情:
mysql> SELECT *
-> FROM performance_schema.metadata_locks
-> WHERE OBJECT_TYPE = 'USER LEVEL LOCK' \\G
*************************** 1. row ***************************
OBJECT_TYPE: USER LEVEL LOCK
OBJECT_SCHEMA: NULL
OBJECT_NAME: my_lock_1
COLUMN_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140483603134144
LOCK_TYPE: EXCLUSIVE
LOCK_DURATION: EXPLICIT
LOCK_STATUS: GRANTED
SOURCE: item_func.cc:5452
OWNER_THREAD_ID: 49
OWNER_EVENT_ID: 139
*************************** 2. row ***************************
OBJECT_TYPE: USER LEVEL LOCK
OBJECT_SCHEMA: NULL
OBJECT_NAME: my_lock_2
COLUMN_NAME: NULL
OBJECT_INSTANCE_BEGIN: 93976377610320
LOCK_TYPE: EXCLUSIVE
LOCK_DURATION: EXPLICIT
LOCK_STATUS: GRANTED
SOURCE: item_func.cc:5452
OWNER_THREAD_ID: 50
OWNER_EVENT_ID: 62
*************************** 3. row ***************************
OBJECT_TYPE: USER LEVEL LOCK
OBJECT_SCHEMA: NULL
OBJECT_NAME: my_lock_1
COLUMN_NAME: NULL
OBJECT_INSTANCE_BEGIN: 93976377962800
LOCK_TYPE: EXCLUSIVE
LOCK_DURATION: EXPLICIT
LOCK_STATUS: PENDING
SOURCE: item_func.cc:5452
OWNER_THREAD_ID: 50
OWNER_EVENT_ID: 69
3 rows in set (0.00 sec)
以上是关于Mysql 死锁过程及案例详解之用户自定义锁的主要内容,如果未能解决你的问题,请参考以下文章
Mysql 死锁过程及案例详解之清空缓存锁Flush Lock
Mysql 死锁过程及案例详解之清空缓存锁Flush Locks
Mysql 死锁过程及案例详解之元数据锁MetaData Lock
Mysql 死锁过程及案例详解之元数据锁MetaData Lock
Mysql 死锁过程及案例详解之记录锁与间隔锁Record Lock Gap Lock
Mysql 死锁过程及案例详解之插入意向锁与自增锁备份锁日志锁Insert Intention Lock Auto-increment Lock Backup Lock Log Lock