MySQL 中的悲观锁和乐观锁都是应对并发访问时产生的问题,但它们的工作原理和使用场景不同。

    悲观锁是指在数据读取、修改过程中,认为每一次操作都有可能会有其他事务来修改这个数据,因此为了保证访问的安全性采用的一种悲观策略。当一个事务想要对某个数据进行操作时,它会先把该数据加锁,确保其他事务不能同时访问,从而避免了竞争条件下的数据不一致问题。悲观锁适用于需要修改大量数据或者数据更新比较频繁的场景,例如银行转账等操作。

    乐观锁是相对于悲观锁的一种方案。它假定数据一般情况下不会出现修改冲突,所以每次不会去先加锁再执行操作,而直接去执行操作,在提交更新前,会判断此期间是否有其他事务对这个同样的数据进行了修改,如果有,则放弃本次修改。乐观锁适用于读多写少,数据争用情况较低的场景。

    具体到 MySQL 数据库,InnoDB 存储引擎支持悲观锁和乐观锁的实现:

    • 悲观锁可以通过在 SQL 语句末尾添加 FOR UPDATE 关键字,该语句会自动为该行或数据集上锁。例如,SELECT * FROM table1 WHERE id=1 FOR UPDATE;。
    • 乐观锁可以通过使用版本控制机制来实现。通常情况下,需要为表添加一个版本号字段,每次更新时将其加一,当发生冲突时,会检查更新前后的版本是否一致,若不一致则认为发生了冲突,回滚操作。示例代码如下:
    1. // 读取原始数据
    2. String sql = "SELECT name, version FROM mytable WHERE id=1";
    3. ResultSet rs = stmt.executeQuery(sql);
    4. rs.next();
    5. String name = rs.getString("name");
    6. int version = rs.getInt("version");
    7. // 修改数据
    8. name = "new_name";
    9. version++;
    10. // 提交修改
    11. sql = "UPDATE mytable SET name='" + name + "', version=" + version + " WHERE id=1 AND version=" + (version-1);
    12. int rows = stmt.executeUpdate(sql);
    13. if (rows == 0) {
    14. // 修改失败,抛出异常或者重试
    15. }

    总之,悲观锁和乐观锁各有适用场景,应根据业务需求选择合适的锁策略并加以实现。