如何使用mysql实现分布式锁

在分布式系统中,多个进程或服务可能会同时访问和修改共享资源,为了保证数据的一致性和完整性,需要使用分布式锁来控制对共享资源的访问。MySQL 可以用来实现分布式锁,下面为你详细介绍实现方法和步骤。

基于数据库表实现分布式锁

思路

通过在数据库中创建一个表,利用数据库的事务和唯一索引特性来实现分布式锁。当一个线程需要获取锁时,尝试向该表中插入一条记录,由于唯一索引的存在,如果插入成功,则表示获取锁成功;如果插入失败,则表示锁已被其他线程占用。

实现步骤

  1. 创建锁表
CREATE TABLE `distributed_lock` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `lock_name` VARCHAR(255) NOT NULL UNIQUE,  -- 锁的名称,使用唯一索引
    `create_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

在这个表中,lock_name 字段用于标识不同的锁,通过设置为唯一索引,保证同一时间只有一条记录的 lock_name 是相同的。
  1. 获取锁
-- 开启事务
START TRANSACTION;
INSERT INTO `distributed_lock` (`lock_name`) VALUES ('your_lock_name')
ON DUPLICATE KEY UPDATE id = id;
-- 判断是否插入成功
SELECT ROW_COUNT();

在上述 SQL 语句中,使用 INSERT ... ON DUPLICATE KEY UPDATE 语句尝试插入一条记录。如果 lock_name 不存在,则插入成功,ROW_COUNT() 返回 1,表示获取锁成功;如果 lock_name 已经存在,则不会插入新记录,ROW_COUNT() 返回 0,表示锁已被其他线程占用。
  1. 释放锁
DELETE FROM `distributed_lock` WHERE `lock_name` = 'your_lock_name';
-- 提交事务
COMMIT;

当线程完成对共享资源的操作后,通过删除 distributed_lock 表中对应的记录来释放锁。

示例代码(Python + MySQL)

 
import mysql.connector

def acquire_lock(lock_name):
    conn = mysql.connector.connect(
        host="localhost",
        user="your_username",
        password="your_password",
        database="your_database"
    )
    cursor = conn.cursor()
    try:
        conn.start_transaction()
        cursor.execute("INSERT INTO `distributed_lock` (`lock_name`) VALUES (%s) ON DUPLICATE KEY UPDATE id = id", (lock_name,))
        result = cursor.rowcount
        conn.commit()
        return result == 1
    except Exception as e:
        conn.rollback()
        print(f"Error acquiring lock: {e}")
        return False
    finally:
        cursor.close()
        conn.close()

def release_lock(lock_name):
    conn = mysql.connector.connect(
        host="localhost",
        user="your_username",
        password="your_password",
        database="your_database"
    )
    cursor = conn.cursor()
    try:
        cursor.execute("DELETE FROM `distributed_lock` WHERE `lock_name` = %s", (lock_name,))
        conn.commit()
    except Exception as e:
        conn.rollback()
        print(f"Error releasing lock: {e}")
    finally:
        cursor.close()
        conn.close()

# 使用示例
lock_name = "test_lock"
if acquire_lock(lock_name):
    try:
        print("Lock acquired, doing some work...")
        # 模拟业务操作
        import time
        time.sleep(5)
    finally:
        release_lock(lock_name)
        print("Lock released.")
else:
    print("Failed to acquire lock.")
 

基于 MySQL 的 GET_LOCK() 函数实现分布式锁

思路

MySQL 提供了 GET_LOCK() 函数来实现简单的分布式锁。该函数用于获取一个命名锁,如果锁可用,则获取锁并返回 1;如果锁已被其他会话占用,则阻塞等待,直到锁被释放或超时,超时后返回 0;如果发生错误,则返回 NULL

实现步骤

  1. 获取锁
SELECT GET_LOCK('your_lock_name', 10);  -- 尝试获取锁,超时时间为 10 秒

在上述 SQL 语句中,'your_lock_name' 是锁的名称,10 是超时时间(单位:秒)。

  1. 释放锁
SELECT RELEASE_LOCK('your_lock_name');

使用 RELEASE_LOCK() 函数释放锁。

示例代码(Python + MySQL)

import mysql.connector

def acquire_lock(lock_name, timeout):
    conn = mysql.connector.connect(
        host="localhost",
        user="your_username",
        password="your_password",
        database="your_database"
    )
    cursor = conn.cursor()
    try:
        cursor.execute(f"SELECT GET_LOCK('{lock_name}', {timeout})")
        result = cursor.fetchone()[0]
        return result == 1
    except Exception as e:
        print(f"Error acquiring lock: {e}")
        return False
    finally:
        cursor.close()
        conn.close()

def release_lock(lock_name):
    conn = mysql.connector.connect(
        host="localhost",
        user="your_username",
        password="your_password",
        database="your_database"
    )
    cursor = conn.cursor()
    try:
        cursor.execute(f"SELECT RELEASE_LOCK('{lock_name}')")
        result = cursor.fetchone()[0]
        return result == 1
    except Exception as e:
        print(f"Error releasing lock: {e}")
        return False
    finally:
        cursor.close()
        conn.close()

# 使用示例
lock_name = "test_lock"
timeout = 10
if acquire_lock(lock_name, timeout):
    try:
        print("Lock acquired, doing some work...")
        # 模拟业务操作
        import time
        time.sleep(5)
    finally:
        if release_lock(lock_name):
            print("Lock released.")
        else:
            print("Failed to release lock.")
else:
    print("Failed to acquire lock.")
 

优缺点分析

  • 优点
    • 实现简单,无需引入额外的中间件。
    • 基于数据库,对于已经使用 MySQL 的系统来说,无需增加新的基础设施。
  • 缺点
    • 性能相对较低,数据库操作会有一定的延迟。
    • 可靠性依赖于数据库的稳定性,如果数据库出现故障,可能会导致锁机制失效。
    • 不适合高并发场景,在高并发情况下,数据库的压力会增大,可能会影响系统的性能。

posted on   数据派  阅读(14)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示