Hibernate:如何修复“从X改为Y的实例的标识符”?

时间:2010-11-14 19:20:10

标签: java hibernate hibernateexception

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

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

19 个答案:

答案 0 :(得分:36)

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

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

答案 1 :(得分:26)

在修改ID字段

之前,您必须从会话中分离您的实体

答案 2 :(得分:16)

就我而言,hbm.xml中的PK字段的类型为“整数”,但在bean代码中它是long

答案 3 :(得分:4)

在我的情况下,我解决了它将@Id字段类型从long更改为Long。

答案 4 :(得分:4)

在我看来,getter和setter名称与Variable name不同。

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;
}

答案 5 :(得分:3)

在我的特定情况下,这是由我的服务实现中需要spring @Transactional(readOnly = true)注释的方法引起的。一旦我补充说,问题就解决了。但不寻常,这只是一个选择声明。

答案 6 :(得分:3)

在我的情况下,模板有一个拼写错误,所以不是检查等价(==),而是使用赋值等于(=)。

所以我改变了模板逻辑:

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

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

现在一切都很好。所以,也要检查你的观点!

答案 7 :(得分:3)

确保在更改ID时不要多次尝试使用同一个User对象。换句话说,如果您在批处理类型操作中执行某些操作:

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);
}

答案 8 :(得分: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)
);

RelationWithUnique实体的Entity类看起来基本上是这样的:

@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的暗示,我只是错过了它。

答案 9 :(得分:1)

问题也可以出现在不同类型的对象的PK中(&#34;用户&#34;在你的情况下)并输入你要求hibernate获取session.get(type, id);

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

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

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

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

面对同样的问题。 我有两个豆之间的关联。在bean A中,我将变量类型定义为Integer,在bean B中,我将变量定义为Long。 我将它们都更改为Integer。这解决了我的问题。

答案 14 :(得分:0)

这是您的更新方法中的问题。在保存更改之前,只需实例化新用户,就可以了。如果您在DTO和Entity类之间使用映射,那么请在映射之前进行此操作。

我也有这个错误。我有用户对象,试图更改他的位置,用户表中的位置为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);
}  

答案 15 :(得分:0)

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

instanceA.setInstanceB(new InstanceB());
instanceA.setInstanceB(YOUR NEW VALUE);

答案 16 :(得分:0)

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

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

就我而言,我正在使用映射框架(MapStruct)更新实体。在此过程中,还更新了其他引用的实体,因为映射框架默认会这样做。后来我用新实体替换了原始实体(按照数据库术语,更改了外键的值以引用相关表中的另一行),先前引用的实体的主键已经更新,并且休眠尝试在刷新时继续执行此更新。

答案 17 :(得分:0)

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

答案 18 :(得分:0)

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