我正在使用Springboot开发授权微服务。我有权限、角色和用户的概念,每一个都表示为一个@Entity
类,并有相应的JpaRepository
。
每个@Entity
类都有一个@IdClass
,它由一个字符串ID和一个时间戳组成(该字段称为createdAt
)。其思想是,对其中一个实体对象的任何修改都将在数据库中创建一个新行。我无法修改此数据库架构。我遇到了在更新时修改ID(时间戳部分)抛出HibernateExeption
的问题。我的解决方案是使用@PrePersist
来修改时间戳。
@PrePersist
private void updateTimestamp() {
createdAt = Instant.now();
}
这似乎对我的权限实体起作用。然而,当我测试更新我的角色实体时,我现在得到以下错误
org.hibernate.HibernateException: identifier of an instance of com.example.auth.model.Role was altered from RoleId(roleId=TEST_ROLE_R2, createdAt=2023-09-04T21:52:39.860899Z) to RoleId(roleId=TEST_ROLE_R2, createdAt=2023-08-31T23:12:25.927743Z)
用同样的@PrePersist
方法
另一件奇怪的事情是,异常似乎是在访问权限存储库时抛出的。更新/创建角色时,将引用关联权限的信息。
在引发异常的
permissionRepository.findMostRecentPermissionById(p)
findMostRecentPermisisonById()
@Query(
value = "SELECT * FROM auth.permissions WHERE permissionID = :permissionID ORDER BY createdat DESC LIMIT 1",
nativeQuery = true
)
Permission findMostRecentPermissionById(String permissionID);
我根本不确定是什么导致了异常的抛出,我特别困惑的是为什么在这里抛出它。在代码的其他部分使用findMostRecentPermissionById
方法时不会导致任何问题。任何见解或建议将不胜感激。
更新
我仍然不明白为什么异常会在原来的位置抛出。但是,使用entityManager.detach(entity)
允许我手动设置时间戳字段并添加一个新实体。
1条答案
按热度按时间kgqe7b3p1#
我不确定您的模式设计的正确性-通常这种愿望(即,维护一组对象版本并主要查询最新版本)是通过更复杂的方法实现的,例如:
但是,Hibernate不支持更改实体标识符,这在documentation中有明确说明:
Hibernate和JPA都对相应的数据库列做了以下假设:
从技术上讲,上述内容适用于数据库中的列,但同样适用于实体类。
回答最初的问题“为什么它有时有效,有时无效?“
实际行为取决于持久化上下文是否知道要修改的实体,如果持久化上下文没有关于要修改的实体的信息,它认为该实体是新的,一切都“按预期”工作,否则抛出异常,例如: