浅谈MySQL对于SELECT语句是否会自动加锁

 更新时间:2026年07月30日 14:44:30   作者:宁小法先森︿( ̄︶ ̄)︿  
MySQL SELECT语句的加锁机制取决于事务隔离级别和查询方式,本文就来详细的介绍一下MySQL对于SELECT语句是否会自动加锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

MySQL 对于 SELECT 语句是否加锁取决于​​事务隔离级别​​和​​查询方式​​,以下是全面分析:

一、不同隔离级别下的 SELECT 加锁行为

隔离级别普通 SELECT 是否加锁说明
READ UNCOMMITTED❌ 不加锁可能读取未提交数据(脏读)
READ COMMITTED❌ 不加锁基于 MVCC 读取最新提交版本
REPEATABLE READ❌ 不加锁基于 MVCC 读取事务开始时快照
SERIALIZABLE✅ 加共享锁 (S锁)所有 SELECT 自动转为 LOCK IN SHARE MODE

二、显式加锁的 SELECT 语句

即使在不自动加锁的隔离级别,可以通过以下方式强制加锁:

1. 加排他锁 (FOR UPDATE)

SELECT * FROM orders 
WHERE user_id = 5 
FOR UPDATE; -- 加 X 锁,阻塞其他写操作

2. 加共享锁 (LOCK IN SHARE MODE)

SELECT * FROM products 
WHERE stock > 0 
LOCK IN SHARE MODE; -- 加 S 锁,允许并发读但阻塞写

三、特殊场景下的隐式加锁

1. 外键约束检查

DELETE FROM parent_table WHERE id = 10;
-- 子表的 SELECT 检查会加共享锁

2. 唯一键冲突检查

INSERT INTO users (email) VALUES ('test@example.com');
-- 插入前的唯一性检查会加共享锁

3. INSERT ... SELECT

INSERT INTO archive_users
SELECT * FROM users 
WHERE created_at < '2020-01-01'; 
-- 对源表 users 的扫描可能加锁

四、InnoDB 的 MVCC 机制

MySQL 通过多版本并发控制实现非锁定读:

graph TD
    A[事务开始] --> B[创建Read View]
    B --> C{查询}
    C -->|读取| D[最新提交版本]
    C -->|修改| E[创建新版本]
    E --> F[写入Undo Log]

五、查看 SELECT 锁状态

1. 查看当前锁

SELECT * FROM performance_schema.data_locks 
WHERE THREAD_ID = PS_CURRENT_THREAD_ID();

2. 监控锁等待

SELECT * FROM sys.innodb_lock_waits;

六、各隔离级别下的锁表现对比

操作RURCRRSerializable
普通 SELECT无锁无锁无锁共享锁
UPDATE行级X锁行级X锁行级X锁+间隙锁行级X锁
INSERT隐式X锁隐式X锁隐式X锁+间隙锁隐式X锁
DELETE行级X锁行级X锁行级X锁+间隙锁行级X锁

七、最佳实践建议

​优先使用默认的 RR 隔离级别​

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

​只对需要加锁的查询使用 FOR UPDATE​

-- 仅当需要后续更新时加锁
START TRANSACTION;
SELECT balance FROM accounts WHERE id=1 FOR UPDATE;
UPDATE accounts SET balance = balance - 100 WHERE id=1;
COMMIT;

​避免长时间持有锁​

-- 设置锁等待超时
SET innodb_lock_wait_timeout = 30;

​监控长事务​

SELECT * FROM information_schema.INNODB_TRX 
ORDER BY TIME_MS DESC LIMIT 10;

​使用覆盖索引减少锁冲突​

-- 创建覆盖索引
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
-- 使用覆盖索引查询
SELECT order_id FROM orders 
WHERE user_id = 5 AND status = 'pending';

总结

在 MySQL 的默认隔离级别(REPEATABLE READ)下:

  • ​普通 SELECT 语句不会加任何锁​​,通过 MVCC 机制实现非阻塞读
  • 只有显式使用 FOR UPDATELOCK IN SHARE MODE 时会加锁
  • SERIALIZABLE 隔离级别会自动为 SELECT 加共享锁

理解这些机制对于设计高并发应用至关重要,既能保证数据一致性,又能最大化系统吞吐量。

到此这篇关于浅谈MySQL对于SELECT语句是否会自动加锁的文章就介绍到这了,更多相关MySQL SELECT自动加锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Mysql导出数据的几种方式

    详解Mysql导出数据的几种方式

    MySQL导出数据的目的有很多种,如数据库备份、表结构导出、表数据导出、分析数据采取等,本文详细的介绍了两种Mysql导出数据的方法,感兴趣的小伙伴可以了解一下
    2018-10-10
  • MySQL中OFFSET 越大越慢怎么解决

    MySQL中OFFSET 越大越慢怎么解决

    本文主要介绍了深分页问题优化策略,探讨LIMIT OFFSET分页性能瓶颈,提出延迟关联、游标分页及子查询优化三种方案,帮助解决大OFFSET值下性能下降问题
    2026-06-06
  • MySQL中的锁和MVCC机制解读

    MySQL中的锁和MVCC机制解读

    MySQL事务、锁和MVCC机制是确保数据库操作原子性、一致性和隔离性的关键,事务必须遵循ACID原则,锁的类型包括表级锁、行级锁和意向锁,MVCC通过非锁定读和锁定读实现并发控制,幻读和死锁是并发事务中常见的问题,可以通过预防策略和优化技巧解决
    2025-01-01
  • mysql设置update时间字段自动更新的实现

    mysql设置update时间字段自动更新的实现

    本文主要介绍了在MySQL中实现时间字段的自动更新功能,通过设置on update CURRENT_TIMESTAMP属性来避免在更新时手动更新时间字段,具有一定的参考价值,感兴趣的可以了解一下
    2025-10-10
  • mysql安装报错unknown variable mysqlx_port=0.0

    mysql安装报错unknown variable mysqlx_port=0.0

    本文主要介绍了mysql安装报错unknown variable mysqlx_port=0.0,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-06-06
  • 详解MySQL的内连接和外连接

    详解MySQL的内连接和外连接

    这篇文章主要介绍了详解MySQL的内连接和外连接,mySQL包含两种联接,分别是内连接(inner join)和外连接(out join),但我们又同时听说过左连接,交叉连接等术语,本文就带大家来了解一下,需要的朋友可以参考下
    2023-05-05
  • MySQL中update语法的使用记录

    MySQL中update语法的使用记录

    在MySQL中,UPDATE 语句用于修改已存在的表中的记录,下面通过示例介绍MySQL中update语法的使用记录,感兴趣的朋友一起看看吧
    2024-07-07
  • MySQL重命名表名的实现示例

    MySQL重命名表名的实现示例

    在MySQL中,可以通过RENAMETABLE和ALTERTABLE命令来重命名表,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-10-10
  • MySQL常用类型转换函数总结(推荐)

    MySQL常用类型转换函数总结(推荐)

    这篇文章主要介绍了MySQL常用类型转换函数总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • mysql 8.0.12 winx64下载安装教程

    mysql 8.0.12 winx64下载安装教程

    这篇文章主要为大家详细介绍了mysql 8.0.12 winx64下载安装教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09

最新评论