Hibernate Spring数据JPA从UPDATE@Query返回列

Hibernate Spring数据JPA从UPDATE@Query返回列,hibernate,spring-data-jpa,Hibernate,Spring Data Jpa,考虑以下场景(从真实世界的示例转换而来),我在DB中预先生成了需要分配给用户的引用 因此,我的数据库结构如下所示: CREATE TABLE reference ( reference_id VARCHAR(20) PRIMARY KEY, group_id INT NOT NULL, assigned_at TIMESTAMP WITH TIME ZONE, username VARCHAR(256) ) 我的存储库看起来像这样 @Repos

考虑以下场景(从真实世界的示例转换而来),我在DB中预先生成了需要分配给用户的引用

因此,我的数据库结构如下所示:

CREATE TABLE reference
(
    reference_id VARCHAR(20) PRIMARY KEY,
    group_id     INT NOT NULL,
    assigned_at  TIMESTAMP WITH TIME ZONE,
    username     VARCHAR(256)
)
我的存储库看起来像这样

@Repository
public interface ReferenceRepository extends JpaRepository<Reference, String> {
    
    @Query(
            value = "UPDATE reference " +
                    "SET username    = ?2, " +
                    "    assigned_at = now() " +
                    "WHERE reference_id = ( " +
                    "    SELECT reference_id " +
                    "    FROM reference " +
                    "    WHERE username IS NULL " +
                    "      AND group_id = ?1 " +
                    "    LIMIT 1 FOR UPDATE SKIP LOCKED) " +
                    "RETURNING reference_id;"
            nativeQuery = true)
    String assignReference(int groupId, String userName);
@存储库
公共接口引用position扩展了jpareposition{
@质疑(
value=“更新引用”+
“设置用户名=?2,”+
“分配的_at=now()”+
“其中引用_id=(”+
“选择引用\u id”+
“来自引用”+
“其中用户名为空”+
“和组_id=?1”+
“更新跳过的限制1已锁定)”+
“正在返回引用\u id;”
nativeQuery=true)
字符串assignReference(int-groupId,字符串用户名);

目前它工作正常(这是从@Transactional service调用的),但我只是想知道它是否有效地使用@Query,或者它可能会导致一些我目前看不到的错误。

这可能是高度特定于数据库和驱动程序的,但除此之外,我看不到真正的问题

关于为什么这是特定于数据库/驱动程序的:

  • 由于您使用的是
    @Query
    注释,而没有
    @修改
    ,因此,如果查询有效与否,则查询将像select语句一样执行。这是一个如何编写驱动程序的问题。但我不希望在没有通知的情况下更改,因为我希望作者意外地以这种方式实现它

  • 实际上,我很惊讶,更新的
    在子选择中起作用。这可能不是所有数据库都是如此。无论如何,语法本身就是依赖于数据库的AFAIK


您可以通过Blaze Persistence实现这一点,Blaze Persistence是一个位于JPA/Hibernate之上的库:

使用Blaze Persistence的查询生成器API进行的查询如下所示:

List<Long> ids = criteriaBuilderFactory.update(entityManager, Reference.class, "r")
    .set("username", userName)
    .setExpression("assignedAt", "CURRENT_TIMESTAMP")
    .where("r.id").in()
        .from(Reference.class, "rSub")
        .select("rSub.id"))
        .where("rSub.username").isNull()
        .where("rSub.group.id").eq(groupId)
        .setMaxResults(1)
    .end()
    .executeWithReturning("id", Long.class);
List id=criteriaBuilderFactory.update(entityManager,Reference.class,“r”)
.set(“用户名”,用户名)
.setExpression(“assignedAt”,“当前时间戳”)
。其中(“r.id”)。在()
.from(Reference.class,“rSub”)
.选择(“rSub.id”))
.where(“rSub.username”).isNull()
.where(“rSub.group.id”).eq(groupId)
.setMaxResults(1)
(完)
.executeWithReturning(“id”,Long.class);
不幸的是,子查询中的锁定还不能用Blaze持久化建模,但查询的其余部分将与您预期的一样

不确定您是否正在使用PostgreSQL,但在这种情况下,您可以使用建议锁,它作为函数提供,也可以在子查询中使用