如何更新Spring Data JPA @Modifying @Query查询中的JPA / Hibernate @Version字段?

时间:2017-05-09 15:09:35

标签: java hibernate spring-data-jpa

对于测试@Version注释,我使用以下设置来管理持久性:

  • Spring Boot Starter 1.5.3.RELEASE
  • Hibernate 5.2.10.Final
  • Spring Data Envers 1.1.3.RELEASE - > Spring Data JPA 1.11.3.RELEASE

测试数据库:

  • H2
  • 的PostgreSQL
  • MariaDB的
  • 甲骨文

实体正在使用@Version带注释的字段,该字段为incremented on update。一个示例实体看起来像这样:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Version;

@Entity
@Table(name = "\"users\"")
public class User {

    @Id
    private Long id;

    private boolean active;

    @Version
    @Column(nullable = false)
    private long version = 0L;

    // getters/setters (not shown)

}

除了CRUD之外,基于Spring Data JPA的UserRepository提供了自定义修改查询

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User, Long> {

    @Modifying
    @Query("UPDATE User u SET u.active = false WHERE u.id = ?1")
    void deactivate(Long id);

    @Modifying
    @Query("UPDATE User u SET u.active = false WHERE u.id IN :ids")
    void deactivateAll(@Param("ids") Long... ids);

    @Modifying
    @Query("UPDATE User u SET u.active = false WHERE u.id IN :ids")
    void deactivateAll(@Param("ids") Iterable<Long> ids);

}

由于版本字段未自动增加JPQL / HQL查询,因此必须通过相应调整自定义查询来手动手动

尝试使用特定于Hibernate的(符合非JPA标准) VERSIONED 关键字(仅限HQL)来扩展查询时

@Modifying
@Query("UPDATE VERSIONED User u SET u.active = false WHERE u.id = ?1")
void deactivate(Long id);
生成的SQL无效与测试的数据库无关,导致错误看起来像这样(模式名称为TEST):

  

表&#34; USER0 _&#34;未找到; SQL语句:更新&#34; TEST&#34;。&#34;用户&#34;组   user0 _。&#34; version&#34; = user0 _。&#34; version&#34; +1,&#34; active&#34; = 0 where(&#34; id&#34;)IN   (选择&#34; id&#34;来自&#34; HT_users&#34;)[42102-194]

那么,如何更新Spring Data JPA @Modifying @Query查询中的JPA / Hibernate @Version字段?

2 个答案:

答案 0 :(得分:1)

您可以添加 u.version=u.version+1 查询。更新后的@Query看起来像这样:

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User, Long> {

    @Modifying
    @Query("UPDATE User u SET u.version=u.version+1, u.active = false WHERE u.id = ?1")
    void deactivate(Long id);

    @Modifying
    @Query("UPDATE User u SET u.version=u.version+1, u.active = false WHERE u.id IN :ids")
    void deactivateAll(@Param("ids") Long... ids);

    @Modifying
    @Query("UPDATE User u SET u.version=u.version+1, u.active = false WHERE u.id IN :ids")
    void deactivateAll(@Param("ids") Iterable<Long> ids);

}

使用此功能可能会有一些警告。例如这显然不会因为EntityManager do(as described here)发出的 OptimisticLockException更新而失败。

答案 1 :(得分:0)

回答类似的问题here - 尝试在UPDATE关键字后添加VERSIONED关键字:

@Modifying
@Query("UPDATE VERSIONED User...)