在 MySQL 中,乐观锁和悲观锁是两种常见的并发控制机制,用于解决多个事务同时操作相同数据时可能引发的冲突问题。它们的主要区别在于对数据冲突的处理方式。
1. 悲观锁(Pessimistic Locking)
1.1 概念
- 悲观锁假设数据冲突很可能会发生,因此在访问数据时直接加锁,确保其他事务无法修改数据,直到当前事务完成。
- 适用于写操作较多的场景。
1.2 实现方式
在 MySQL 中,悲观锁通常通过以下方式实现:
SELECT ... FOR UPDATE
:对查询结果加排他锁(X 锁),其他事务无法修改或加锁。SELECT ... LOCK IN SHARE MODE
:对查询结果加共享锁(S 锁),其他事务可以读取但不能修改。
1.3 示例
-- 事务 1
START TRANSACTION;
SELECT * FROM users WHERE id = 1 FOR UPDATE; -- 加排他锁
UPDATE users SET balance = balance - 100 WHERE id = 1;
COMMIT;
-- 事务 2
START TRANSACTION;
SELECT * FROM users WHERE id = 1 FOR UPDATE; -- 等待事务 1 释放锁
UPDATE users SET balance = balance + 100 WHERE id = 1;
COMMIT;
1.4 优缺点
- 优点:
- 保证数据一致性,避免冲突。
- 缺点:
- 加锁会降低并发性能。
- 可能导致死锁。
2. 乐观锁(Optimistic Locking)
2.1 概念
- 乐观锁假设数据冲突不太可能发生,因此在访问数据时不加锁,而是在提交事务时检查数据是否被其他事务修改过。
- 适用于读操作较多的场景。
2.2 实现方式
乐观锁通常通过以下方式实现:
- 版本号(Version):在表中增加一个版本号字段,每次更新数据时版本号加 1。
- 时间戳(Timestamp):在表中增加一个时间戳字段,每次更新数据时更新时间戳。
2.3 示例
-- 表结构
CREATE TABLE users (
id INT PRIMARY KEY,
balance DECIMAL(10, 2),
version INT DEFAULT 0
);
-- 事务 1
START TRANSACTION;
SELECT balance, version FROM users WHERE id = 1; -- 读取当前余额和版本号
-- 假设读取到的 balance = 1000, version = 1
UPDATE users SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = 1; -- 检查版本号
COMMIT;
-- 事务 2
START TRANSACTION;
SELECT balance, version FROM users WHERE id = 1; -- 读取当前余额和版本号
-- 假设读取到的 balance = 1000, version = 1
UPDATE users SET balance = balance + 100, version = version + 1
WHERE id = 1 AND version = 1; -- 检查版本号
COMMIT;
- 如果事务 1 先提交,事务 2 的
UPDATE
会失败(因为版本号已变为 2),此时事务 2 需要重试。
2.4 优缺点
- 优点:
- 不加锁,提高并发性能。
- 适用于读多写少的场景。
- 缺点:
- 需要处理冲突(如重试机制)。
- 实现复杂度较高。
3. 乐观锁 vs 悲观锁
特性 | 乐观锁 | 悲观锁 |
---|---|---|
加锁时机 | 提交时检查冲突 | 访问数据时加锁 |
实现方式 | 版本号或时间戳 | SELECT ... FOR UPDATE |
适用场景 | 读多写少 | 写多读少 |
性能 | 高并发性能 | 低并发性能 |
冲突处理 | 需要处理冲突(如重试) | 直接加锁,避免冲突 |
复杂度 | 实现较复杂 | 实现简单 |
4. 选择建议
- 使用悲观锁的场景:
- 数据冲突概率较高。
- 写操作较多。
- 需要强一致性保证。
- 使用乐观锁的场景:
- 数据冲突概率较低。
- 读操作较多。
- 需要高并发性能。
5. 总结
- 悲观锁:通过加锁避免冲突,适合写多读少的场景,但可能降低并发性能。
- 乐观锁:通过版本号或时间戳检测冲突,适合读多写少的场景,但需要处理冲突。
根据实际业务场景选择合适的锁机制,可以有效提升数据库的并发性能和数据一致性。
THE END
暂无评论内容