Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL SELECT自动加锁

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

作者:宁小法先森︿( ̄︶ ̄)︿

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)下:

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

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

您可能感兴趣的文章:
阅读全文