我需要我的应用具有以下行为:
场景1
用户A查看订单。
用户B查看相同的订单。
场景2
我使用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("...");
}
要使用此功能,我必须
问题在于,在步骤2中,实体和DTO版本可能相同。但随后在步骤3中,版本可能会有所不同。有没有办法让休眠状态作为单个原子操作执行检查和更新,例如:
delete from [Order] where orderId = ? and version = ?
如果没有删除则抛出StaleObjectStateException
。
更新
我发现了两种可行的方法。这两种方法之一存在问题吗?第二种方法涉及较少的数据库访问。客户通常一次只会发送一个删除订单,因此此处的性能不成问题。
方法1
对于每个要删除的订单:
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);
方法2
添加OrderRepository方法:
int deleteByIdAndVersion(Long id, Integer version);
对于每个要删除的订单:
int x = orderRepository.deleteByIdAndVersion(orderIdFromClient, versionFromClient);
if (x==0) {
throw new OptimisticLockException();
}