identifier of an instance of bean was altered from 1 to 2(持久化对象ID变更)

本文记录了一个关于使用Hibernate框架时遇到的问题:修改外键ID时抛出异常。通过清除缓存的方法解决了该问题,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天遇到个怪问题,hibernate修改外键id时出现:

org.springframework.orm.hibernate3.HibernateSystemException: identifier of an instance of xx altered from 2677 to 2672; 
nested exception is org.hibernate.HibernateException: identifier of an instance of com.yongjun.tdms.model.CustomerRelationship.contactArchives.ContactArchives altered from 2677 to 2672

Caused by: org.hibernate.HibernateException: identifier of an instance of xx altered from 2677 to 2672
	at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:51)
	...
	at java.lang.Thread.run(Thread.java:619)


结果在网上看到大神的解决方法

引用:

应该是缓存导致,save前先clear()试试
dao.clear();
dao.save(entity);

自己加了个:

	public void storeContractAdditionalInfo(ContractAdditionalInfo ai){
		super.getHibernateTemplate().clear();//加的清缓存
		super.store(ai);
	}

ok,问题解决。希望对大家有帮助


                
<think>我们正在处理一个关于Hibernate异常的报错:identifier ofan instanceof ...was alteredfrom ...to null。根据引用[1]和引用[3]的描述,这个错误通常发生在试图更改实体类的主键(identifier)时,特别是将主键从非空值改为null。错误原因分析:在Hibernate中,实体类的主键(通常是id)一旦被设定,就不应该再被修改。因为Hibernate使用主键来唯一标识一个实体对象,并在其Session缓存中跟踪该对象。如果试图改变一个已持久化实体的主键值,Hibernate会抛出这个异常。根据引用[3]中的代码片段,我们可以看到问题发生的场景: ```public intreceiveDogInfo(Dog dog) {dog.setIsMarked("1");dog.setSource("0");intresult =0;dog.setOldId(dog.getId());//将原来的id保存到oldId字段dog.setId(null);//试图将id设置为nulldog.setUpdateTime(new Date());dog.setCreateTime(new Date());result =DogDao.save(dog);returnresult;} ```在这段代码中,程序试图将实体对象`dog`的id(主键)设置为null,然后进行保存。这会导致Hibernate抛出异常。解决方案:1.不要修改已持久化实体的主键。主键应该是不可变的。2.如果目的是创建一个新的实体,那么应该创建一个新的对象,而不是重用原来的对象并修改其主键。3.在上述代码中,看起来是想保存一个新的`Dog`实体,但是使用了已有的`dog`对象,并试图将其id设为null。正确的做法是创建一个新的`Dog`对象,然后将需要复制的属性(除了主键)从旧对象复制到新对象,然后保存新对象。修改后的代码示例: ```javapublic intreceiveDogInfo(Dog dog) {DognewDog= newDog();//创建一个新的对象//复制属性,除了主键idnewDog.setIsMarked("1");newDog.setSource("0");newDog.setOldId(dog.getId());//如果需要,将原id保存到oldId字段//注意:不设置新对象id,因为新实体保存时会由数据库生成主键(如果是自增)newDog.setUpdateTime(new Date());newDog.setCreateTime(newDate());//复制其他需要的属性...intresult =DogDao.save(newDog);//保存新对象returnresult;} ```注意:如果主键是手动分配的(非自增),那么新对象需要设置一个非空的主键值,但绝对不能是原来旧对象的主键(除非旧对象已经被删除且主键可以重用,但通常不建议这样做)。在大多数情况下,主键是自增的,所以不需要设置,由数据库自动生成。另外,引用[2]提到的“undeclaredidentifier”错误是C语言中的编译错误,与当前问题无关。总结:避免修改实体对象的主键,特别是将其设置为null。如果需要创建新记录,请创建新的实体对象。相关问题:1. Hibernate中实体主键的设计原则是什么?2.如何正确地在Hibernate中保存一个新实体?3. Hibernate中实体对象的生命周期有哪些状态?</think>### 实例标识符被修改为 null 的故障排除 根据错误信息 `identifier of an instance of ... was altered from ... to null`,这通常发生在 Hibernate/JPA 框架中,当实体对象的主键(identifier)被意外修改为 null 时。以下是常见原因和解决方案: #### 常见原因分析 1. **主键被显式置空** 在业务代码中显式调用 `setId(null)`(如引用[3]所示),违反 Hibernate 实体主键不可变原则: ```java dog.setId(null); // 错误操作:主键被置空 ``` 2. **实体对象状态混乱** - 游离状态(detached)实体被错误当作新实体保存 - 持久化状态(persistent)实体的主键被修改 3. **级联操作问题** 在关联关系(如 `@OneToMany`)中,子实体主键处理不当(如引用[1]场景) 4. **主键生成策略冲突** 使用 `GenerationType.IDENTITY` 时手动设置主键值导致冲突 #### 解决方案 1. **禁止修改持久化实体主键** 持久化实体的主键一旦生成就不可更改: ```java // 正确做法:创建新对象而非修改主键 Dog newDog = new Dog(); newDog.setName(dog.getName()); // 复制属性 // newDog.setId(null); // 不需要显式置空(自动生成) DogDao.save(newDog); ``` 2. **检查实体状态** 使用 `entityManager.contains(entity)` 判断实体状态: ```java if(entityManager.contains(dog)) { // 禁止修改主键 } else { // 可安全保存为新实体 } ``` 3. **修复级联操作** 在关联关系中明确指定 `cascade` 类型: ```java @OneToMany(cascade = CascadeType.PERSIST) // 明确级联类型 private List<Dog> dogs; ``` 4. **正确使用主键策略** 避免手动设置自动生成的主键: ```java @Id @GeneratedValue(strategy = GenerationType.IDENTITY) // 自动生成 private Long id; // 不要手动setId() ``` #### 预防措施 - 实体类添加主键保护(推荐): ```java public class BaseEntity { @Id private Long id; // 防止主键被意外修改 public void setId(Long id) { if(this.id != null && id == null) { throw new IllegalStateException("禁止置空主键"); } this.id = id; } } ``` - 使用 DTO 对象接收前端数据,避免直接操作实体主键 - 启用 Hibernate 调试日志:`logging.level.org.hibernate=DEBUG` > 此错误本质是违反了 JPA 规范中 **实体主键不可变** 原则[^1][^3]。解决方案的核心是保持主键的不可变性和正确管理实体状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值