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