悲观锁与乐观锁

悲观锁

概念

悲观锁的核心思想是 "悲观" 地认为在对共享资源进行操作时,一定会有其他线程或事务来修改该资源。所以在操作之前,会先对资源进行加锁,以防止其他线程或事务的干扰,确保操作的独占性。

实现方式
  • 数据库层面 :在数据库中,常用的悲观锁实现方式是使用 FOR UPDATE 语句。例如,在 MySQL 中,执行 SELECT ... FOR UPDATE 语句会对查询结果中的记录加上行级锁,其他事务在这些记录被锁定期间无法对其进行修改或删除操作,直到当前事务提交或回滚释放锁。

sql

复制代码
-- 假设在一个事务中执行以下语句
START TRANSACTION;
SELECT * FROM users WHERE id = 1 FOR UPDATE;
-- 对查询到的记录进行修改操作
UPDATE users SET balance = balance - 100 WHERE id = 1;
COMMIT;
  • 编程语言层面 :在 Java 中,synchronized 关键字和 ReentrantLock 类都可以实现悲观锁。synchronized 关键字可以修饰方法或代码块,当一个线程进入被 synchronized 修饰的方法或代码块时,会自动获取锁,其他线程需要等待该线程释放锁才能进入。

java

复制代码
public class PessimisticLockExample {
    private int count = 0;
    private final Object lock = new Object();

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }
}
使用场景

悲观锁适用于写操作频繁、冲突可能性较高的场景。例如,在银行系统中,对用户账户余额的修改操作通常使用悲观锁,以确保在一个事务对账户进行修改时,不会有其他事务同时修改该账户,避免出现数据不一致的问题。

乐观锁

概念

乐观锁持有 "乐观" 的态度,它认为在大多数情况下,多个线程或事务对共享资源的操作不会发生冲突,所以在操作之前不会加锁。只有在更新资源时,才会检查该资源是否被其他线程或事务修改过,如果没有被修改,则进行更新操作;如果被修改了,则采取相应的处理措施,如重试或报错。

实现方式
  • 版本号机制:在数据库表中增加一个版本号字段(通常为整数类型),每次对记录进行修改时,版本号会加 1。在更新记录时,会比较当前版本号与数据库中记录的版本号是否一致,如果一致则更新记录并将版本号加 1,如果不一致则表示记录已被其他事务修改,更新失败。

sql

复制代码
-- 假设 users 表中有 id、balance 和 version 字段
-- 查询记录并获取当前版本号
SELECT id, balance, version FROM users WHERE id = 1;
-- 更新记录时检查版本号
UPDATE users SET balance = balance - 100, version = version + 1 WHERE id = 1 AND version = 1;
  • 时间戳机制:与版本号机制类似,只是使用时间戳来代替版本号。每次对记录进行修改时,会更新记录的时间戳。在更新记录时,会比较当前时间戳与数据库中记录的时间戳是否一致。
使用场景

乐观锁适用于读操作频繁、写操作较少、冲突可能性较低的场景。例如,在电商系统中,商品的库存信息通常会被大量用户读取,但只有在用户下单时才会进行写操作,这种情况下可以使用乐观锁来提高系统的并发性能。

对比

  • 性能方面:悲观锁由于在操作之前就加锁,会导致其他线程或事务需要等待锁的释放,可能会降低系统的并发性能。而乐观锁在大多数情况下不需要加锁,只有在更新时才进行检查,因此在并发度较高的场景下,乐观锁的性能通常优于悲观锁。
  • 冲突处理:悲观锁通过加锁来避免冲突,保证了数据的一致性,但会增加死锁的风险。乐观锁在冲突发生时,需要进行额外的处理,如重试或报错,可能会导致一定的性能开销。
  • 使用场景:悲观锁适用于写操作频繁、冲突可能性较高的场景,而乐观锁适用于读操作频繁、写操作较少、冲突可能性较低的场景。
相关推荐
A__tao几秒前
SQL 转 Java 实体类工具
java·数据库·sql
喝可乐的布偶猫5 分钟前
Java类变量(静态变量)
java·开发语言·jvm
m0_6530313614 分钟前
腾讯云认证考试报名 - TDSQL数据库交付运维专家(TCCE PostgreSQL版)
运维·数据库·腾讯云
TDengine (老段)29 分钟前
TDengine STMT2 API 使用指南
java·大数据·物联网·时序数据库·iot·tdengine·涛思数据
喝可乐的布偶猫40 分钟前
韩顺平之第九章综合练习-----------房屋出租管理系统
java·开发语言·ide·eclipse
Code季风1 小时前
深入理解微服务中的服务注册与发现(Consul)
java·运维·微服务·zookeeper·架构·go·consul
光军oi1 小时前
java微服务(Springboot篇)——————IDEA搭建第一个Springboot入门项目
java·spring boot·微服务
小马哥编程1 小时前
【iSAQB软件架构】架构决策记录-ADR
数据库·架构·系统架构·设计规范
萧鼎1 小时前
深度探索 Py2neo:用 Python 玩转图数据库 Neo4j
数据库·python·neo4j
future14122 小时前
C#每日学习日记
java·学习·c#