如何在通过SpringDataJPA执行批量更新时更新@Version字段
我正在使用spring数据存储库,我有一个问题,我找不到答案。我的存储库查询是:如何在通过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; 当我执行查询时,版本字段不会更新,但如果不是查询,
@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%'