You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

MySQL查询行无锁实现及表锁定/解锁方法咨询

MySQL表锁定/解锁 & 无锁查询指南

Hey there! Let's break down your questions one by one since you're getting up to speed with MySQL locking behavior.

一、表级锁定与解锁的基本操作

MySQL支持手动对表加锁,不过不同存储引擎的锁机制差异很大,先讲通用的表锁操作:

1. 加表锁

  • 共享读锁(READ):多个会话可以同时加读锁,允许其他会话读,但禁止写操作:
    LOCK TABLES your_table_name READ;
    
  • 排他写锁(WRITE):只有当前会话能读写该表,其他会话的读写都会阻塞:
    LOCK TABLES your_table_name WRITE;
    

2. 解锁

执行以下语句手动释放所有当前会话持有的表锁:

UNLOCK TABLES;

另外,当你的MySQL会话断开时,所有持有的表锁会自动释放。

注意:InnoDB引擎默认是行级锁为主,只有在特定场景下才会升级为表锁;而MyISAM引擎则完全依赖表级锁,这一点需要根据你使用的存储引擎区分对待。

二、关于MySQL中没有NOLOCK关键字的问题

你说得没错——MySQL没有NOLOCK这个官方关键字,这是SQL Server特有的查询提示。为什么你执行带NOLOCK的查询没报错?因为MySQL会把它当作无效的语法忽略(如果是放在注释里则直接被跳过),不会触发报错,但也不会产生任何无锁的效果。

比如你写SELECT * FROM your_table WITH (NOLOCK);,MySQL会识别为语法错误吗?其实要看具体写法,如果你把NOLOCK放在注释里(比如SELECT * FROM your_table /* NOLOCK */),那自然不会报错,但完全没作用。总之,别指望NOLOCK在MySQL里实现无锁读。

三、实现查询行无锁的标准方式

在InnoDB引擎(现在MySQL的默认引擎)中,无锁读的核心是MVCC(多版本并发控制),这也是MySQL实现类似SQL Server NOLOCK效果的标准方式,具体分几种场景:

1. 普通SELECT的默认行为(快照读)

在默认的READ COMMITTEDREPEATABLE READ隔离级别下,不加任何锁提示的SELECT语句都是快照读

  • 它不会对目标行加任何锁,也不会被其他会话的排他锁阻塞
  • 读取的是数据的一致性快照(不是最新的实时数据,但保证事务一致性)
  • 完全不影响其他会话的写操作

这就是最常用的无锁读方式,比如:

SELECT * FROM your_table WHERE id = 1;

2. 强制无锁读(针对特殊隔离级别)

如果你的会话使用的是SERIALIZABLE隔离级别(最高隔离级别),普通SELECT会变成“当前读”,自动加共享行锁。这时候要实现无锁读,可以临时切换隔离级别:

-- 临时设置当前会话的隔离级别为读提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 执行无锁查询
SELECT * FROM your_table WHERE ...;
-- 可以再切换回原来的隔离级别(如果需要)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

3. 跳过被锁行(可选场景)

如果你希望查询时直接跳过被其他会话锁定的行(而不是等待锁释放),可以使用MySQL 8.0+支持的SKIP LOCKED提示:

SELECT * FROM your_table WHERE id IN (1,2,3) FOR UPDATE SKIP LOCKED;

注意:这个是跳过锁行,不是无锁读,它本身是加排他锁的,只是跳过已被锁的行,适合特定的并发场景(比如任务队列)。

4. MyISAM引擎的无锁读(不推荐)

如果你的表用的是MyISAM引擎(现在很少用了),它默认是表级读锁,所有SELECT都会阻塞写操作。要实现无锁读,只能切换到READ UNCOMMITTED隔离级别:

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM your_table WHERE ...;

但这种方式会读到脏数据(未提交的修改),所以一般不推荐,建议换成InnoDB引擎。


内容的提问来源于stack exchange,提问作者Francesco Rizzi

火山引擎 最新活动