解释乐观锁和悲观锁的概念,并在 Java 中如何实现这两种锁机制,分别举一个简单的例子?

乐观锁和悲观锁是两种处理并发控制的不同策略,它们各有侧重,适用于不同的场景。下面我会用生活化的例子来帮助你理解这两种锁机制,并展示在Java中如何简单地实现它们。

乐观锁

概念:乐观锁假定在大部分情况下,数据不会发生并发冲突,所以在操作数据前不会加锁,只是在更新数据的时候检查在此期间数据是否被其他事务修改过。乐观锁的核心在于"先做事,后检查"。

例子:想象你和朋友一起去图书馆借书,乐观锁的策略就像是你认为这本书多半没人借,所以你直接去前台登记借书,登记时再确认书有没有被别人借走。如果书被借走了,你就重新找一本或者等待。

Java实现:乐观锁通常借助版本号或时间戳来实现。比如,我们在数据库表中添加一个版本字段version,每次更新数据时,同时更新版本号。

复制代码
1public class Book {
2    private int id;
3    private String title;
4    private int version; // 版本号
5
6    // 更新书籍的方法,使用乐观锁
7    public boolean updateTitle(String newTitle) {
8        // 假设这里有一段SQL,类似 "UPDATE book SET title = ?, version = version + 1 WHERE id = ? AND version = ?"
9        // 如果更新的行数为0,说明版本号不对,即数据已被其他人修改
10        int updatedRows = dao.updateTitleAndVersion(id, newTitle, version);
11        if (updatedRows > 0) {
12            version++; // 如果更新成功,本地版本号也需要+1
13            return true;
14        }
15        return false;
16    }
17}

悲观锁

概念:悲观锁采取较为保守的态度,认为数据在操作过程中很可能会被其他事务修改,因此在操作数据前就会加锁,阻止其他事务的修改操作,直到当前事务完成。悲观锁的核心思想是"先拿锁,后做事"。

例子:还是借书的情景,悲观锁就像是你担心书随时会被别人借走,所以你一开始就拿着这本书去柜台排队,直到借书手续完成才放手,期间别人不能借走这本书。

Java实现:在Java中,悲观锁的实现通常依赖于数据库层面的锁机制,如行级锁。使用JDBC时,可以通过设置事务隔离级别和使用SELECT ... FOR UPDATE来实现悲观锁。

复制代码
1Connection conn = dataSource.getConnection();
2try {
3    conn.setAutoCommit(false); // 开启事务
4    PreparedStatement ps = conn.prepareStatement("SELECT * FROM book WHERE id = ? FOR UPDATE");
5    ps.setInt(1, bookId);
6    ResultSet rs = ps.executeQuery();
7    if (rs.next()) {
8        // 处理数据,比如检查库存、更新信息等
9        // ...
10        
11        // 执行更新操作
12        // ...
13        
14        conn.commit(); // 提交事务
15    }
16} catch (SQLException e) {
17    conn.rollback(); // 出错回滚事务
18} finally {
19    conn.close();
20}
  • 乐观锁适用于并发冲突较少的场景,它通过版本控制减少锁定时间,提高并发性能,但需要额外的逻辑来处理冲突。
  • 悲观锁则适用于并发冲突频繁的场景,它通过提前加锁确保数据一致性,但可能会导致较高的锁竞争和等待时间,影响并发性能。

选择哪种锁,取决于你对数据并发访问的预期和对性能的要求。在实际应用中,还需要根据具体业务场景和数据库特性综合考虑。

相关推荐
仙俊红8 小时前
Integer\int对比,equals()\hashcode面试
java·面试·职场和发展
njsgcs8 小时前
用clip把设计经验变成向量数据库,然后每秒检索可以检查3维模型设计的错误吗
数据库
WiChP8 小时前
【V0.1B10】从零开始的2D游戏引擎开发之路
java·数据库·游戏引擎
一然明月8 小时前
qt基本用法
开发语言·qt
云烟成雨TD8 小时前
Spring AI Alibaba 1.x 系列【60】检查点机制原理与全流程剖析
java·人工智能·spring
小当家.1058 小时前
PostgreSQL 做向量数据库:pgvector 在 RAG 中的实战与多场景适配
数据库·人工智能·postgresql·rag
ForgeAI码匠8 小时前
Maven 多模块项目如何避免越写越乱?Forge Admin 的模块边界实践
java·人工智能·开源·maven
hef2888 小时前
Prism图形设计从入门到精通:外观设置、图层顺序与微调技巧
开发语言
z落落8 小时前
C# 数组 最终完整版全套笔记(一维+多维+交错+引用类型+对象数组)
java·笔记·c#
Access开发易登软件8 小时前
Access 和 SQLite,根本不在一个赛道上
java·jvm·数据库·sqlite·excel·vba·access开发