You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL中JPA更新报错‘identifier of an instance...’求解决

解决Hibernate "identifier of an instance of ...was altered from ..." 更新报错问题

我搜了大量关于“identifier of an instance of ...was altered from ...”的相关内容,没找到能解决我问题的方案。用的PostgreSQL数据库,对应的数据表只有id_type和libelle两列。创建、读取、删除功能都正常,只有更新功能失效,相关代码如下:

Model层代码

package com.stev.pillecons.pilleCons.models;   

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity(name = "type_pille")
@JsonIgnoreProperties({"hibernateLazyInitializer","handler"})
public class LePille {
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private int id_type;
    private String libelle;
    public  LePille(){}
    public String getLibelle() {
        return libelle;
    }
    public void setLibelle(String libelle) {
        this.libelle = libelle;
    }
    public int getId_type() {
        return id_type;
    }
    public void setId_type(int id_type) {
        this.id_type = id_type;
    }
}

Service层代码

@Override
public LePille updatePille(Integer id, LePille  Sourcepille) {
    Optional<LePille> existingSession = pilleRepo.findById(id);

    if (existingSession.isPresent())
    {
        LePille  Targetpile = existingSession.get();
        BeanUtils.copyProperties(Sourcepille, Targetpile);
        return pilleRepo.saveAndFlush(Targetpile);
    }
    else
    {
        throw new PilleException("pille not found");
    }
}

Controller层代码

@RequestMapping(value = "{id}", method = RequestMethod.PUT)
public ResponseEntity update(@PathVariable Integer id, @RequestBody LePille session) {
  LePille updPille =   pilleService.updatePille(id, session);
    return new ResponseEntity<LePille>(updPille, HttpStatus.OK);
}

调试信息

通过Postman发起PUT请求,传入的数据是{"id_type":10,"libelle":"dsf"},调试时发现:

  • SourcePille的值为{"id_type":0,"libelle":"popo"}
  • Targetpile的值为{"id_type":10,"libelle":"dsf"}

问题原因

报错的核心是Hibernate不允许修改持久化实体的主键值,而你的代码中BeanUtils.copyProperties会把传入对象的id_type(主键)复制到从数据库查询出的实体对象上,导致原有主键被覆盖,触发Hibernate的主键变更检测报错。


解决方案

方案1:排除主键字段复制

修改BeanUtils.copyProperties的调用,明确排除主键字段id_type,只复制需要更新的业务字段:

BeanUtils.copyProperties(Sourcepille, Targetpile, "id_type");

方案2:移除主键的setter方法(推荐)

因为你的主键采用IDENTITY自增策略,业务上不需要修改主键,直接删除实体类中的setId_type方法,从根源上避免主键被修改:

// 删除这个方法
public void setId_type(int id_type) {
    this.id_type = id_type;
}

方案3:手动复制更新字段

放弃使用BeanUtils,手动复制需要更新的字段,更安全可控:

LePille Targetpile = existingSession.get();
Targetpile.setLibelle(Sourcepille.getLibelle()); // 仅更新libelle字段
return pilleRepo.saveAndFlush(Targetpile);

额外优化

Controller中同时接收了路径参数id和请求体中的id_type,建议以路径参数id为准,忽略请求体中的主键值,避免出现参数不一致的情况。比如在Controller中可以直接设置:

session.setId_type(id);

或者在Model层通过@JsonIgnore注解忽略请求体中的id_type字段,确保主键只由数据库自增生成。


内容的提问来源于stack exchange,提问作者user609511

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 08:50:38