【问题标题】:Hibernate Postgresql select for update with outer join issueHibernate Postgresql 选择更新外连接问题
【发布时间】:2017-09-18 14:40:28
【问题描述】:

我在尝试使用带有 Hibernate 作为 JPA 实现和 Postgresql 的 Spring 数据选择更新行时遇到了问题。

假设我们有实体:A、B、C。

public class A{
   @Id
   private Long id;

   @OneToMany(fetch = FetchType.EAGER)
   private Set<B> bSet;

   @OneToMany(fetch = FetchType.EAGER)
   private Set<C> cSet;
}

假设我们要选择包含所有相关 B 和 C 实体的 A 进行更新,即锁定与 A 表相关的行。

@Query(SELECT a FROM A a 
       LEFT JOIN FETCH a.bSet
       LEFT JOIN FETCH a.cSet
       WHERE a.id=?)
@Lock(LockModeType.PESSIMISTIC_WRITE)
public A selectAndLockA(Long Aid);

查询看起来像

SELECT a.column1, ... from tableA a LEFT JOIN tableB b ... FOR UPDATE of a,c

用于更新 a,c

查询将尝试锁定两个表,这会导致异常,例如: org.postgresql.util.PSQLException: 错误: FOR UPDATE 不能应用于外连接的可空端

我尝试归档的只是锁定第一个表“FOR UPDATE OF a”

是否可以以某种方式配置或告诉 Hibernate 仅锁定第一个表。

【问题讨论】:

    标签: postgresql hibernate jpa spring-data


    【解决方案1】:

    PostreSQL 不支持此功能。如果您执行外部 SELECT,则没有什么可以阻止某人将行插入到 LEFT JOINED 表中,从而修改您正在查看的结果集(例如,在重复读取时,列将不再为 NULL)。

    详细解释见here

    【讨论】:

      【解决方案2】:

      问题已经有很长时间了,但我有类似的问题,希望我的回答能帮助到别人。

      假设我们有这个 JPA 实体:

      @Entity
      @Table(name = "card_transactions")
      public class CardTransactionsEntity {
          @Id
          @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "card_trans_seq")
          @SequenceGenerator(name = "card_trans_seq", sequenceName = "card_trans_seq")
          private Long id;
      
          @ManyToOne(fetch = FetchType.LAZY)
          @JoinColumns({
                  @JoinColumn(name = "ofd_id", referencedColumnName = "ofd_id"),
                  @JoinColumn(name = "receipt_id", referencedColumnName = "receipt_id")})
          private ReceiptsEntity receipt;
      
          @Column
          @Enumerated(EnumType.STRING)
          private CardTransactionStatus requestStatus;
      
          ...
      
      }
      
      @Entity
      @Table(name = "receipts")
      public class ReceiptsEntity {
          @EmbeddedId
          private OfdReceiptId id; 
      
          ...
      }
      
      @Embeddable
      public class OfdReceiptId implements Serializable {
      
          @Column(name = "ofd_id")
          @Enumerated(EnumType.STRING)
          private OfdId ofdId;
      
          @Column(name = "receipt_id")
          private String receiptId;
      
          ...
      }
      

      并且我们希望选择 CardTransactionsEntity 和获取的 ReceiptsEntity 用于悲观更新 CardTransactionsEntity。这可以使用 Hibernate 和 Spring Data JPA 存储库来完成

      public interface CardTransactionRepository extends JpaRepository<CardTransactionsEntity, Long> {
      
          @Query("select ct from CardTransactionsEntity ct left join fetch ct.receipt r where ct.requestStatus = :requestStatus")
          @Lock(value = LockModeType.PESSIMISTIC_WRITE)
          @QueryHints(value = {
                  @QueryHint(name = "javax.persistence.lock.timeout", value = "-2"), // LockOptions.SKIP_LOCKED
                  @QueryHint(name = "org.hibernate.lockMode.r", value = "NONE") // "r" is alias for ct.receipt and will excluded from PESSIMISTIC_WRITE
          })
          List<CardTransactionsEntity> loadCardTransactions(@Param("requestStatus") CardTransactionStatus requestStatus, Pageable pageable);
      
      }
      

      这个存储库方法会像这样执行查询

      SELECT ct.*, r.* from card_transactions ct LEFT OUTER JOIN receipts r ON ct.ofd_id = r.ofd_id and ct.receipt_id = r.receipt_id WHERE ct.request_status=? LIMIT ? FOR UPDATE OF ct SKIP LOCKED
      

      【讨论】:

        【解决方案3】:

        您可以通过使用 FetchType.LAZY 连接表来绕过此错误。此获取类型是默认类型,不需要为 @OneToMany 连接指定。

        public class A{
           @Id
           private Long id;
        
           @OneToMany
           private Set<B> bSet;
        
           @OneToMany
           private Set<C> cSet;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-04-08
          • 2012-02-04
          • 1970-01-01
          • 2021-11-18
          • 2011-04-10
          • 2011-07-28
          • 2016-01-14
          相关资源
          最近更新 更多