在MySQL中,乐观锁和悲观锁是两种处理并发控制的策略,用于解决多用户同时访问和修改同一数据时可能产生的冲突。它们各有特点,适用于不同的场景。

    1. 悲观锁 (Pessimistic Locking)

    核心思想:假设会发生并发冲突,因此在整个数据处理过程中都对数据进行加锁,防止其他事务修改。

    实现方式: 在MySQL中,主要通过SELECT … FOR UPDATE或SELECT … LOCK IN SHARE MODE语句来实现。 SELECT … FOR UPDATE:在读取数据的同时加上排他锁(X锁),其他事务无法读取(在可重复读隔离级别下)或修改该数据,直到当前事务提交或回滚。 SELECT … LOCK IN SHARE MODE:加上共享锁(S锁),其他事务可以读但不能修改。

    示例: sql — 开启事务 START TRANSACTION;

    — 查询并锁定账户A的余额 SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;

    — 执行业务逻辑(如转账) UPDATE accounts SET balance = balance - 100 WHERE id = 1;

    — 提交事务,释放锁 COMMIT;

    优点: 数据一致性高,能有效防止脏读、不可重复读、幻读等问题。 适合写操作频繁、并发冲突高的场景。

    缺点: 性能开销大,长时间持有锁会阻塞其他事务,降低并发度。 可能导致死锁。

    适用场景: 银行转账、库存扣减等强一致性要求的场景。

    1. 乐观锁 (Optimistic Locking)

    核心思想:假设不会发生并发冲突,在提交更新时才检查是否违反了数据一致性。如果发现冲突,则回滚或重试。

    实现方式: 通常通过在表中增加一个版本号字段(version)或时间戳字段来实现。

    示例: sql — 假设有表 accounts,包含 id, balance, version 字段 — 查询数据(记录当前版本号) SELECT id, balance, version FROM accounts WHERE id = 1;

    — 业务逻辑处理…

    — 更新时检查版本号是否变化 UPDATE accounts SET balance = balance - 100, version = version + 1 WHERE id = 1 AND version = 1; — 这里的1是之前查询到的版本号

    — 检查影响行数,如果为0说明更新失败(版本不匹配)

    优点: 不加锁,读操作无阻塞,性能高,并发能力强。 适合读多写少的场景。

    缺点: 无法保证绝对的一致性,更新可能失败,需要应用层处理重试逻辑。 在高并发写场景下,冲突频繁,重试成本高。

    适用场景: 文章点赞、评论计数、配置信息更新等冲突较少的场景。

    对比总结

    特性 悲观锁 乐观锁


    假设 总会发生冲突 很少发生冲突 加锁时机 读取时即加锁 更新时检查版本 性能 低并发,高一致性 高并发,低开销 实现 FOR UPDATE, LOCK IN SHARE MODE version 或 timestamp 字段 适用场景 写密集、强一致性要求 读密集、冲突少 选择建议 如果业务对数据一致性要求极高,且并发写入频繁,推荐使用悲观锁。 如果系统读操作远多于写操作,且冲突概率低,推荐使用乐观锁以提升性能。

    在实际开发中,可以根据具体业务需求灵活选择,甚至在同一系统中混合使用两种策略。