我正在尝试在Postgres数据库上使用JPA和Hibernate实现悲观写锁定表,而不锁定相关表。
当前配置:
- Java 17
- Spring Boot 3.0.7
- Hibernate 6.1.7.Final
- Postgres 14.7
我没有使用显式的Hibernate方言声明。根据this - Hibernate应该自动配置方言。
我的当前JPA存储库代码:
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({
@QueryHint(name = AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, value = "" + Integer.MIN_VALUE),
@QueryHint(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "false"),
@QueryHint(name = AvailableSettings.JAKARTA_LOCK_TIMEOUT, value = "-2"),
@QueryHint(name = "org.hibernate.lockMode.ps", value = "NONE")
})
@Query(value = """
SELECT p
FROM Payment p
JOIN FETCH p.status ps
WHERE ps.name IN :statuses
""")
Stream<Payment> getPaymentsStream(@Param("statuses") List<String> statuses);
我期望什么:
SELECT p1_0.*, --just skipped fields
s1_0.id,
s1_0.name
FROM
payment p1_0
JOIN payment_status s1_0 ON
s1_0.id = p1_0.status_id
s1_0.name IN(?,?)
FOR UPDATE OF p1_0 SKIP LOCKED
我得到什么
SELECT p1_0.*, --just skipped fields
s1_0.id,
s1_0.name
FROM
payment p1_0
JOIN payment_status s1_0 ON
s1_0.id = p1_0.status_id
s1_0.name IN(?,?)
select id from payment_status where id =? for update skip locked
select id from payment where id =? for update skip locked
我根据this的答案添加了
org.hibernate.lockMode.ps
提示,但没有任何变化。
此外,我已经使用nativeQuery = true
进行了测试,一切正常。但是由于可能存在兼容性问题,我不想使用这种方法。在Hibernate中有没有其他方法可以使
FOR UPDATE OF
起作用而不编写原生查询?提前感谢您。 更新1 实体声明
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@DynamicUpdate
@DynamicInsert
@EqualsAndHashCode
@Table(name = "payment", schema = "xxx")
@ToString
public class Payment implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
/* column definitions */
@ManyToOne
@JoinColumn(name = "status_id", referencedColumnName = "id", nullable = true)
private PaymentStatus status;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@DynamicUpdate
@DynamicInsert
@EqualsAndHashCode
@Table(name = "payment_status", schema = "xxx")
@ToString
public class PaymentStatus implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
}