74
org.hibernate.HibernateException: identifier of an instance 
of org.cometd.hibernate.User altered from 12 to 3

事实上,我的user表确实必须动态改变它的值,我的 Java 应用程序是多线程的。任何想法如何解决它?

4

21 回答 21

56

您是否在某处更改了用户对象的主键值?你不应该那样做。检查您的主键映射是否正确。

您的映射 XML 文件或映射注释是什么样的?

于 2010-11-14T20:08:03.927 回答
34

在修改其 ID 字段之前,您必须从会话中分离您的实体

于 2011-02-15T14:39:08.983 回答
17

在我的例子中,hbm.xml 中的 PK 字段是“整数”类型,但在 bean 代码中是long.

于 2012-07-12T12:48:38.760 回答
6

在我的情况下,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;
}
于 2014-11-30T11:59:17.770 回答
5

就我而言,我解决了将 @Id 字段类型从 long 更改为 Long 的问题。

于 2013-12-17T10:14:41.297 回答
4

确保您在更改 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);
}
于 2015-01-12T11:15:24.523 回答
3

在我的特殊情况下,这是由我的服务实现中需要 spring@Transactional(readOnly = true)注释的方法引起的。一旦我添加了,问题就解决了。不寻常的是,它只是一个选择语句。

于 2011-12-05T14:24:28.907 回答
3

在我的例子中,一个模板有一个错字,所以不是检查等价(==),而是使用赋值等于(=)。

所以我改变了模板逻辑:

if (user1.id = user2.id) ...

if (user1.id == user2.id) ...

现在一切都很好。所以,也请检查您的意见!

于 2014-01-06T07:30:36.053 回答
2

我也面临这个问题。

目标表是一个关系表,连接来自不同表的两个 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的提示,我只是错过了。

于 2015-06-22T21:03:24.210 回答
2

这是您的更新方法中的问题。只需在保存更改之前实例化新用户,就可以了。如果您在 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);
}  
于 2018-10-08T09:47:46.777 回答
2

也遇到了此错误消息,但根本原因与此处其他答案中引用的原因不同。

通用答案:确保一旦休眠加载实体,没有代码以任何方式更改该对象中的主键值。当 hibernate 将所有更改刷新回数据库时,它会抛出此异常,因为主键已更改。如果您没有明确地执行此操作,请寻找可能无意中发生这种情况的地方,也许是在仅配置了 LAZY 加载的相关实体上。

就我而言,我使用映射框架 (MapStruct) 来更新实体。在此过程中,其他引用的实体也正在更新,因为映射框架默认情况下倾向于这样做。后来我用新实体替换了原始实体(在数据库术语中,更改了外键的值以引用相关表中的不同行),先前引用的实体的主键已经更新,并且休眠尝试在刷新时保留此更新。

于 2019-11-22T09:32:56.667 回答
1

问题也可能出现在不同类型的对象的 PK (在您的情况下为“用户”)和您要求休眠获取的类型中session.get(type, id);

在我的情况下,错误是identifier of an instance of <skipped> was altered from 16 to 32. 对象的 PK 类型是Integer,hibernate 被要求输入Long类型。

于 2016-11-23T16:41:52.830 回答
0

在我的情况下,这是因为属性在对象上很长,但在映射 xml 中是 int,这个异常应该更清楚

于 2015-06-17T19:42:52.843 回答
0

如果您使用的是 Spring MVC 或 Spring Boot,请尽量避免: @ModelAttribute("user")在一个控制器中,而在另一个控制器中 model.addAttribute("user", userRepository.findOne(someId);

这种情况会产生这样的错误。

于 2015-08-21T05:40:34.817 回答
0

这是一个老问题,但我将为我的特定问题(Spring Boot、使用 Hibernate 的 JPA、SQL Server 2014)添加修复程序,因为它与此处包含的其他答案不完全匹配:

我有一个外键,例如 my_id = '12345',但引用列中的值是 my_id = '12345'。它最后有一个额外的空间,这是hibernate不喜欢的。我删除了空间,修复了允许这个额外空间的代码部分,一切正常。

于 2017-06-22T14:18:11.220 回答
0

面临同样的问题。我有两个豆子之间的关联。在 bean AI 中将变量类型定义为 Integer,在 bean BI 中定义了与 Long 相同的变量。我将它们都更改为整数。这解决了我的问题。

于 2018-07-25T07:48:08.193 回答
0

我通过实例化一个依赖对象的新实例来解决这个问题。举个例子

instanceA.setInstanceB(new InstanceB());
instanceA.setInstanceB(YOUR NEW VALUE);
于 2019-10-01T14:59:07.043 回答
0

在我的情况下,我在数据库中有一个带有口音的主键,但在其他表中它的外键没有。出于某种原因,MySQL 允许这样做。

于 2021-02-20T15:28:14.420 回答
0

看起来您已经更改了由 JPA 实体上下文管理的 org.cometd.hibernate.User 对象实例的标识符。在这种情况下,创建具有适当 id 的新用户实体对象。并设置它而不是原始的用户对象。

于 2021-07-23T09:49:15.850 回答
0

您是否使用了来自同一服务类的多个事务管理器。例如,如果您的项目有两个或更多事务配置。如果为真,则首先将它们分开。

于 2021-11-15T07:32:22.183 回答
0

当我尝试获取现有的数据库实体、修改了几个字段并执行时遇到了问题

session.save(entity)

代替

session.merge(entity)

由于它存在于数据库中,当我们应该merge()而不是save()

于 2022-02-07T20:40:49.300 回答