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
如何在通过SpringDataJPA执行批量更新时更新@Version字段_Jpa_Version_Jpa 2.0_Spring Data_Spring Data Jpa - Fatal编程技术网

如何在通过SpringDataJPA执行批量更新时更新@Version字段

如何在通过SpringDataJPA执行批量更新时更新@Version字段,jpa,version,jpa-2.0,spring-data,spring-data-jpa,Jpa,Version,Jpa 2.0,Spring Data,Spring Data Jpa,我正在使用spring数据存储库,我有一个问题,我找不到答案。我的存储库查询是: @Modifying @Query("UPDATE User u SET u.firstName = 'blabla' WHERE u.loginName = 'admin'") public int test(); 实体User有一个javax.persistence.Version注释字段: @Version private Long version; 当我执行查询时,版本字段不会更新,但如果不是查询,

我正在使用spring数据存储库,我有一个问题,我找不到答案。我的存储库查询是:

@Modifying
@Query("UPDATE User u SET u.firstName = 'blabla' WHERE u.loginName = 'admin'")
public int test();
实体
User
有一个
javax.persistence.Version
注释字段:

 @Version
 private Long version;
当我执行查询时,版本字段不会更新,但如果不是查询,而是:

User user = this.userRepository.findUserById(1L);
user.setFirstName("blabla");
this.userRepository.save(user);

版本字段已更新。为什么?

JPA 2.0规范第4.10节明确指出:

批量更新直接映射到数据库更新操作,绕过乐观锁定检查。如果需要,便携式应用程序必须手动更新版本列的值,和/或手动验证版本列的值


一般来说,批量更新和删除几乎绕过了持久性提供程序应用的许多功能,在保存实体时可能会用到这些功能。除了乐观锁定之外,这还包括持久性提供程序管理的持久性操作级联。

要使用乐观锁定,首先需要一个
版本

现在,如果bulk update语句没有增加
version
列,则可能会发生丢失更新异常:

现在,为了避免丢失更新,只需增加
version

您可以使用任何类型的查询来执行此操作

JPQL 标准API 增加
version
列后,将在加载由bulk语句更新的实体的早期版本的并发事务中防止丢失更新:

int updateCount = entityManager
.createQuery(
    "update Post " +
    "set " +
    "   status = :newStatus," +
    "   version = version + 1 " +
    "where " +
    "   status = :oldStatus and " +
    "   lower(title) like :pattern")
.setParameter("oldStatus", PostStatus.PENDING)
.setParameter("newStatus", PostStatus.SPAM)
.setParameter("pattern", "%spam%")
.executeUpdate();
CriteriaBuilder builder = entityManager
.getCriteriaBuilder();
 
CriteriaUpdate<Post> update = builder
.createCriteriaUpdate(Post.class);
 
Root<Post> root = update.from(Post.class);
 
Expression<Boolean> wherePredicate = builder
.and(
    builder.equal(
        root.get("status"),
        PostStatus.PENDING
    ),
    builder.like(
        builder.lower(root.get("title")),
        "%spam%"
    )
);
 
Path<Short> versionPath = root.get("version");
Expression<Short> incrementVersion = builder
.sum((short) 1, versionPath);
 
update
.set(root.get("status"), PostStatus.SPAM)
.set(versionPath, incrementVersion)
.where(wherePredicate);
 
int updateCount = entityManager
.createQuery(update)
.executeUpdate();
UPDATE post
SET
  status = 2,
  version = version + 1
WHERE
  status = 0 AND 
  lower(title) LIKE '%spam%'