org.hibernate.HibernateException: identifier of an instance
of org.cometd.hibernate.User altered from 12 to 3
事实上,我的user
表确实必须动态改变它的值,我的 Java 应用程序是多线程的。任何想法如何解决它?
org.hibernate.HibernateException: identifier of an instance
of org.cometd.hibernate.User altered from 12 to 3
事实上,我的user
表确实必须动态改变它的值,我的 Java 应用程序是多线程的。任何想法如何解决它?
您是否在某处更改了用户对象的主键值?你不应该那样做。检查您的主键映射是否正确。
您的映射 XML 文件或映射注释是什么样的?
在修改其 ID 字段之前,您必须从会话中分离您的实体
在我的例子中,hbm.xml 中的 PK 字段是“整数”类型,但在 bean 代码中是long
.
在我的情况下,getter 和 setter 名称与变量名称不同。
private Long stockId;
public Long getStockID() {
return stockId;
}
public void setStockID(Long stockID) {
this.stockId = stockID;
}
它应该在哪里
public Long getStockId() {
return stockId;
}
public void setStockId(Long stockID) {
this.stockId = stockID;
}
就我而言,我解决了将 @Id 字段类型从 long 更改为 Long 的问题。
确保您在更改 ID 时没有多次尝试使用相同的用户对象。换句话说,如果你在批处理类型的操作中做某事:
User user = new User(); // Using the same one over and over, won't work
List<Customer> customers = fetchCustomersFromSomeService();
for(Customer customer : customers) {
// User user = new User(); <-- This would work, you get a new one each time
user.setId(customer.getId());
user.setName(customer.getName());
saveUserToDB(user);
}
在我的特殊情况下,这是由我的服务实现中需要 spring@Transactional(readOnly = true)
注释的方法引起的。一旦我添加了,问题就解决了。不寻常的是,它只是一个选择语句。
在我的例子中,一个模板有一个错字,所以不是检查等价(==),而是使用赋值等于(=)。
所以我改变了模板逻辑:
if (user1.id = user2.id) ...
到
if (user1.id == user2.id) ...
现在一切都很好。所以,也请检查您的意见!
我也面临这个问题。
目标表是一个关系表,连接来自不同表的两个 ID。我对值组合有一个 UNIQUE 约束,替换了 PK。更新元组的值之一时,发生此错误。
这是表的样子(MySQL):
CREATE TABLE my_relation_table (
mrt_left_id BIGINT NOT NULL,
mrt_right_id BIGINT NOT NULL,
UNIQUE KEY uix_my_relation_table (mrt_left_id, mrt_right_id),
FOREIGN KEY (mrt_left_id)
REFERENCES left_table(lef_id),
FOREIGN KEY (mrt_right_id)
REFERENCES right_table(rig_id)
);
实体的 Entity 类RelationWithUnique
基本上如下所示:
@Entity
@IdClass(RelationWithUnique.class)
@Table(name = "my_relation_table")
public class RelationWithUnique implements Serializable {
...
@Id
@ManyToOne
@JoinColumn(name = "mrt_left_id", referencedColumnName = "left_table.lef_id")
private LeftTableEntity leftId;
@Id
@ManyToOne
@JoinColumn(name = "mrt_right_id", referencedColumnName = "right_table.rig_id")
private RightTableEntity rightId;
...
我修复了它
// usually, we need to detach the object as we are updating the PK
// (rightId being part of the UNIQUE constraint) => PK
// but this would produce a duplicate entry,
// therefore, we simply delete the old tuple and add the new one
final RelationWithUnique newRelation = new RelationWithUnique();
newRelation.setLeftId(oldRelation.getLeftId());
newRelation.setRightId(rightId); // here, the value is updated actually
entityManager.remove(oldRelation);
entityManager.persist(newRelation);
非常感谢PK的提示,我只是错过了。
这是您的更新方法中的问题。只需在保存更改之前实例化新用户,就可以了。如果您在 DTO 和实体类之间使用映射,则在映射之前执行此操作。
我也有这个错误。我有用户对象,试图改变他的位置,位置是用户表中的 FK。我解决了这个问题
@Transactional
public void update(User input) throws Exception {
User userDB = userRepository.findById(input.getUserId()).orElse(null);
userDB.setLocation(new Location());
userMapper.updateEntityFromDto(input, userDB);
User user= userRepository.save(userDB);
}
也遇到了此错误消息,但根本原因与此处其他答案中引用的原因不同。
通用答案:确保一旦休眠加载实体,没有代码以任何方式更改该对象中的主键值。当 hibernate 将所有更改刷新回数据库时,它会抛出此异常,因为主键已更改。如果您没有明确地执行此操作,请寻找可能无意中发生这种情况的地方,也许是在仅配置了 LAZY 加载的相关实体上。
就我而言,我使用映射框架 (MapStruct) 来更新实体。在此过程中,其他引用的实体也正在更新,因为映射框架默认情况下倾向于这样做。后来我用新实体替换了原始实体(在数据库术语中,更改了外键的值以引用相关表中的不同行),先前引用的实体的主键已经更新,并且休眠尝试在刷新时保留此更新。
问题也可能出现在不同类型的对象的 PK (在您的情况下为“用户”)和您要求休眠获取的类型中session.get(type, id);
。
在我的情况下,错误是identifier of an instance of <skipped> was altered from 16 to 32
. 对象的 PK 类型是Integer
,hibernate 被要求输入Long
类型。
在我的情况下,这是因为属性在对象上很长,但在映射 xml 中是 int,这个异常应该更清楚
如果您使用的是 Spring MVC 或 Spring Boot,请尽量避免: @ModelAttribute("user")在一个控制器中,而在另一个控制器中 model.addAttribute("user", userRepository.findOne(someId);
这种情况会产生这样的错误。
这是一个老问题,但我将为我的特定问题(Spring Boot、使用 Hibernate 的 JPA、SQL Server 2014)添加修复程序,因为它与此处包含的其他答案不完全匹配:
我有一个外键,例如 my_id = '12345',但引用列中的值是 my_id = '12345'。它最后有一个额外的空间,这是hibernate不喜欢的。我删除了空间,修复了允许这个额外空间的代码部分,一切正常。
面临同样的问题。我有两个豆子之间的关联。在 bean AI 中将变量类型定义为 Integer,在 bean BI 中定义了与 Long 相同的变量。我将它们都更改为整数。这解决了我的问题。
我通过实例化一个依赖对象的新实例来解决这个问题。举个例子
instanceA.setInstanceB(new InstanceB());
instanceA.setInstanceB(YOUR NEW VALUE);
在我的情况下,我在数据库中有一个带有口音的主键,但在其他表中它的外键没有。出于某种原因,MySQL 允许这样做。
看起来您已经更改了由 JPA 实体上下文管理的 org.cometd.hibernate.User 对象实例的标识符。在这种情况下,创建具有适当 id 的新用户实体对象。并设置它而不是原始的用户对象。
您是否使用了来自同一服务类的多个事务管理器。例如,如果您的项目有两个或更多事务配置。如果为真,则首先将它们分开。
当我尝试获取现有的数据库实体、修改了几个字段并执行时遇到了问题
session.save(entity)
代替
session.merge(entity)
由于它存在于数据库中,当我们应该merge()而不是save()