Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate JPA乐观锁定:如果记录已更新,如何防止删除,反之亦然?_Hibernate_Jpa_Spring Data Jpa_Optimistic Locking - Fatal编程技术网

Hibernate JPA乐观锁定:如果记录已更新,如何防止删除,反之亦然?

Hibernate JPA乐观锁定:如果记录已更新,如何防止删除,反之亦然?,hibernate,jpa,spring-data-jpa,optimistic-locking,Hibernate,Jpa,Spring Data Jpa,Optimistic Locking,我需要我的应用程序具有以下行为: @Entity public class Order { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @Version private Integer version; // many other fields 情景1 用户A查看订单 用户B查看相同的订单 用户A删除订单 用户B请求更新订单。这应该失败 情景2

我需要我的应用程序具有以下行为:

@Entity
public class Order {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @Version
    private Integer version;

    // many other fields
情景1

  • 用户A查看订单

  • 用户B查看相同的订单

  • 用户A删除订单
  • 用户B请求更新订单。这应该失败
  • 情景2

  • 用户A查看订单
  • 用户B查看相同的订单
  • 用户A更新订单
  • 用户B请求删除订单。这应该失败
  • 使用JPA(Hibernate via 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()提到了一个标准解决方案:

    if (entity.getVersion() != dto.getVersion()) {
        throw new OptimisticLockException("...");
    }
    
    要使用这个,我必须

  • 使用客户机的订单id从数据库中查找实体
  • 将实体版本与客户端的DTO版本进行比较
  • 执行删除操作
  • 问题是,在步骤2,实体和DTO版本可能相同。但在步骤3,版本可能不同。是否有办法让hibernate作为单个原子操作执行检查和更新,例如:

     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);
    
            int x = orderRepository.deleteByIdAndVersion(orderIdFromClient, versionFromClient);
            if (x==0) {
                throw new OptimisticLockException();
            }
    
    方法2

    添加OrderRepository方法:

    int-deleteByIdAndVersion(长id,整数版本);

    对于每个要删除的订单:

            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);
    
            int x = orderRepository.deleteByIdAndVersion(orderIdFromClient, versionFromClient);
            if (x==0) {
                throw new OptimisticLockException();
            }