面试题:MySQL 的乐观锁和悲观锁是什么?

在 MySQL 中,乐观锁和悲观锁是两种处理并发控制的方法,它们分别适用于不同的场景,并以不同的方式来保证数据的一致性和完整性。

悲观锁(Pessimistic Locking)

概念:
悲观锁假设会发生并发冲突,因此在操作数据时会直接将数据锁定,防止其他事务对相同数据进行修改,直到当前事务完成。这种方式通常通过数据库的行级锁定机制实现。

使用场景:

  • 当预期会有大量的并发写操作时。
  • 对于关键业务数据的更新,要求高度的数据一致性。

实现方式:

  • 在 MySQL 的 InnoDB 存储引擎中,可以通过 SELECT ... FOR UPDATE 或者 SELECT ... LOCK IN SHARE MODE 来实现悲观锁。
  • SELECT ... FOR UPDATE:会对查询到的记录加排他锁,阻止其他事务对该记录进行读取或更新操作,直到当前事务提交或者回滚。
  • SELECT ... LOCK IN SHARE MODE:会对查询到的记录加共享锁,允许其他事务读取这些记录但阻止他们进行更新,直到当前事务结束。

示例:

-- 使用 FOR UPDATE 锁定选定的行
BEGIN;
SELECT * FROM accounts WHERE id = 123 FOR UPDATE;
UPDATE accounts SET balance = balance - 100 WHERE id = 123;
COMMIT;

乐观锁(Optimistic Locking)

概念:
乐观锁则假定不会发生并发冲突,在读取数据时不加锁,而是在提交更新时检查是否有其他事务已经修改了该数据。如果检测到冲突,则拒绝本次更新并提示用户重试操作。

使用场景:

  • 当系统中的读操作远远多于写操作时。
  • 对于那些可以接受偶尔的冲突重试的情况。

实现方式:

  • 乐观锁通常通过版本号(Version Number)或时间戳(Timestamp)机制实现。每次更新数据时都会检查版本号是否一致,如果不一致则说明数据已被其他事务修改过。
  • 版本号字段需要在表结构中预先定义好,并且每次更新数据时都要同时更新这个版本号。

示例:
假设有一个表包含一个 version 字段用于实现乐观锁:

CREATE TABLE products (
    id INT PRIMARY KEY,
    name VARCHAR(255),
    version INT DEFAULT 0
);

-- 更新时检查版本号
UPDATE products 
SET price = 200, version = version + 1 
WHERE id = 1 AND version = 1; -- 假设当前版本为1

在这个例子中,只有当 id=1 的产品版本号仍为 1 时,更新才会成功;否则,表示有其他事务已修改了这条记录,更新失败。

总结

  • 悲观锁适合于写操作频繁的场景,能够确保数据的一致性,但可能导致较高的锁竞争,降低系统的并发性能。
  • 乐观锁更适合于读多写少的环境,它减少了锁的竞争,提高了并发度,但在高冲突率的情况下可能导致更多的重试次数。

选择哪种锁策略取决于具体的业务需求、系统的并发特性以及对数据一致性的要求。

THE END
喜欢就支持一下吧
点赞10 分享