1. Hibernate 的乐观锁
乐观锁(Optimistic Locking) 是一种并发控制策略,它假设多个事务通常不会同时修改同一个数据。因此,不会像悲观锁那样直接加锁,而是等到事务提交时,检查数据是否被其他事务修改。如果数据在读取到修改期间未发生变化,则可以成功提交,否则会抛出异常来阻止提交,从而避免冲突。
实现乐观锁的方式:
乐观锁通常依赖于版本字段(如 version 字段)。- Hibernate 会在
每次更新数据时自动检查该字段的值是否与数据库中的值一致。如果版本字段不同,则说明有其他事务修改了数据,从而阻止当前事务继续提交。
乐观锁的使用场景
- 避免多个用户同时更新同一数据导致的冲突。
- 在读写频率较高,但写操作冲突较少的场景非常适用。
2. Hibernate 乐观锁的实现
1. 实体类配置
在实体类中使用 @Version 注解来定义一个版本字段,这个字段会在每次更新时自动递增。
示例:使用乐观锁的简单场景
假设有一个 Product 实体类,我们希望在对 Product 进行并发修改时启用乐观锁。
import javax.persistence.*;
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "price")
private double price;
// 乐观锁版本字段
@Version
@Column(name = "version")
private Integer version; // 版本字段
// getters 和 setters
}
2. 版本字段的作用
- 每次插入记录时,Hibernate 会将 version 字段的初始值设置为 0。
- 每次更新时,Hibernate 会自动检查该字段的值是否匹配数据库中的值。如果不匹配,则抛出异常来避免并发冲突。
3. 处理并发更新
- 假设现在有两个事务试图同时更新 Product。在执行时,Hibernate 会检查 version 字段,确保只有第一个事务能够成功更新,而第二个事务将抛出异常。
示例代码:事务并发操作
// 事务1: 读取并更新产品价格
Product product = productRepository.findById(1L).orElseThrow();
product.setPrice(product.getPrice() + 10.00); // 更新价格
productRepository.save(product); // 更新并提交
// 事务2: 读取并更新相同的产品价格
Product product2 = productRepository.findById(1L).orElseThrow();
product2.setPrice(product2.getPrice() + 5.00); // 更新价格
productRepository.save(product2); // 更新并提交
事务1:成功读取产品,并更新价格后提交。
事务2:在事务1提交后,再次试图更新同一个产品,但由于 version 不一致,会抛出异常。
4. 捕获并处理 OptimisticLockException
当多个事务导致乐观锁冲突时,Hibernate 会抛出 OptimisticLockException。你可以通过捕获该异常来进行重试或显示相应的错误信息。
import javax.persistence.OptimisticLockException;
try {
Product product = productRepository.findById(1L).orElseThrow();
product.setPrice(product.getPrice() + 10.00);
productRepository.save(product);
} catch (OptimisticLockException e) {
// 处理乐观锁异常,可以选择重试或返回错误信息
System.out.println("并发更新冲突,请稍后重试。");
}
5. 实验场景:手动更新数据库
你可以在数据库中手动更新某个记录的 version 字段,观察并发事务如何处理这个情况。例如,手动将 version 字段从 1 更新为 2,然后尝试让应用中的事务更新该记录,看看是否抛出乐观锁异常。
结论
使用乐观锁可以有效解决并发场景下的数据更新冲突,而不需要像悲观锁那样持有锁直到事务结束。通过 @Version 注解,Hibernate 自动管理并发更新检查,并在出现冲突时抛出异常。

4931

被折叠的 条评论
为什么被折叠?



