hibernate - JPA Optimistic Locking:如果记录已更新,如何防止删除,反之亦然?
问题描述
我需要我的应用程序具有以下行为:
方案 1
用户 A 查看订单。
用户 B 查看相同的订单。
- 用户 A 删除订单。
- 用户 B 请求更新订单。这应该失败。
方案 2
- 用户 A 查看订单
- 用户 B 查看相同的订单
- 用户 A 更新订单。
- 用户 B 请求删除订单。这应该失败。
使用 JPA(通过 Spring Data JPA 休眠),我试图用它@Version
来实现这种乐观的锁定行为:
@Entity
public class Order {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Version
private Integer version;
// many other fields
删除时,UI 客户端向服务器提供一个订单 ID 列表以及每个订单 ID 的版本号。这个 [post( Spring Data JPA: Delete Optimistic Locking semantics ) 提到了一个标准的解决方案:
if (entity.getVersion() != dto.getVersion()) {
throw new OptimisticLockException("...");
}
要使用它,我必须
- 从数据库中查找实体使用来自客户端的订单 ID
- 将实体版本与客户端的 DTO 版本进行比较
- 执行删除。
问题是在第 2 步,实体和 DTO 版本可能相同。但是在第 3 步,版本可能会有所不同。有没有办法让休眠执行检查和更新作为单个原子操作,例如:
delete from [Order] where orderId = ? and version = ?
StaleObjectStateException
如果没有删除,则抛出。
更新
我发现了两种应该可行的方法。这两种方法之一有问题吗?第二种方法涉及较少的数据库访问。客户通常一次只发送一个要删除的订单,因此这里的性能应该不是问题。
方法一
对于要删除的每个订单:
Order order = orderRepository.findById(
orderIdFromClient).orElseThrow(() ->
new OptimisticLockException());
if (!order.getVersion().equals(versionFromClient)) {
throw new OptimisticLockException();
}
// We now know the managed entity has the same version
// as the requested version. If some other transaction
// has changed the entity, Hibernate will rollback and
// throw OptimisticLockException.
orderRepository.delete(order);
方法二
添加一个 OrderRepository 方法:
int deleteByIdAndVersion(Long id, Integer version);
对于要删除的每个订单:
int x = orderRepository.deleteByIdAndVersion(orderIdFromClient, versionFromClient);
if (x==0) {
throw new OptimisticLockException();
}
解决方案
推荐阅读
- tfs - TFS 团队通知不起作用
- go - 语句末尾的意外 int
- python - pycryptodome 模块不能作为轮子导入
- android - 如何有效地找出用户当前位置是否在一个经纬度点附近?
- html - 如何将多个值添加到角度的单个数据属性?
- python - python-sphinx 扩展,如何获取当前对象的名称?
- typeclass - Purescript 行联合
- listview - Xamarin.Forms ListView 中的交替项背景颜色
- c# - wsmprovhost.exe 在关闭 WsManConnectionInfo 后不终止
- amp-html - 向 amp-date-picker 模板添加其他内容