为了测试@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
- Oracle
实体利用@Version注释字段,在更新时将被增加。一个示例实体如下所示:
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)
}
Spring Data JPA基于的UserRepository提供了除CRUD之外的自定义修改查询功能。
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):
“USER0_”表未找到;SQL语句:update “TEST”。“users” set user0_。“version”=user0_。“version”+1,“active”=0 where(“id”)IN(select“id”from“HT_users”)[42102-194]
那么,我该如何在Spring Data JPA @Modifying @Query查询中更新JPA / Hibernate @Version字段?
@Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
代替手动增加版本号。 - Jay Smithversioned
关键字创建了 HQL 查询,它可以正常工作。但是你会收到错误信息Table "USER0_" not found
。这与versioned
关键字有关吗?在 Hibernate 文档 中提到,您不能显式地修改version
。 - Jay Smithsession.createQuery
方法创建了HQL查询。 - Jay SmithVERSIONED
关键字。关于锁定注释,我提出了另一个 SO 问题以澄清是否可能,参见此处:https://dev59.com/yKHia4cB1Zd3GeqPWaB0 - AntiTiming