【问题标题】:Facing exception HibernateException: identifier of an instance of <Class> was altered from <old> to <new> spring面对异常 HibernateException:<Class> 实例的标识符已从 <old> 更改为 <new> spring
【发布时间】:2026-01-10 02:40:01
【问题描述】:

我正在使用带有 lombok、mapstruct 和 postgresSQL 的 spring。

我在父/子关系的单向@ManyToOne 关系上遇到错误,我的班级客户

这是我的客户端类:

@Getter
@Setter
@Table(name = "client")
public class Client extends AbstractEntity {

    private String name;

    @ManyToOne(cascade = CascadeType.ALL)
    private Address address;

    private boolean headOffice;

    @ManyToOne(cascade= CascadeType.ALL)
    @JoinColumn(name="client_parent_id")
    public Client clientParent;
}

这是我的 abstractEntity 来生成 Id 和一些数据:

@MappedSuperclass
@Getter
@Setter
@RequiredArgsConstructor
public class AbstractEntity {

    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(
            name = "UUID",
            strategy = "org.hibernate.id.UUIDGenerator"
    )
    private String id;

    @CreationTimestamp
    private Timestamp createdDate;

    @UpdateTimestamp
    private Timestamp modifiedDate;
}

这是我的客户服务:

@Service
public class ClientService {

    private final ClientRepository clientRepository;
    private final ClientMapper clientMapper;

    ClientService(ClientRepository clientRepository, ClientMapper clientMapper) {
        this.clientRepository = clientRepository;
        this.clientMapper = clientMapper;
    }

    Client getClient(String id) throws FunctionalException {
        return this.clientRepository.getById(id)
                .orElseThrow(
                        () -> new FunctionalException("Client not found")
                );
    }

    public ClientDto createOrUpdateClient(ClientDto clientDto, String id) throws FunctionalException {

        Client client;
        if (id == null) {
            verifyInExistence(clientDto);
            client = this.clientMapper.toEntity(clientDto);
        } else {
            client = this.getClient(id);
            this.clientMapper.updateClientFromDto(clientDto, client);
        }
        verifyParent(client, clientDto.getClientParentId());

        return this.clientMapper.toDto(this.clientRepository.save(client));
    }

    private void verifyParent(Client client, String parentId) {
        if (parentId != null) {
            client.setClientParent(this.getClient(parentId));
        } else {
            client.setClientParent(null);
        }
    }

    private void verifyInExistence(ClientDto clientDto) throws FunctionalException {
        clientRepository.findByName(clientDto.getName()).ifPresent(s -> {
            throw new FunctionalException(String.format("Client '%s' already exist", clientDto.getName()));
        });
    }
}

还有我的休息控制器:

@RestController
@RequestMapping(path = "/api/client")
public class ClientResource {

    private final ClientService clientService;

    ClientResource(ClientService clientService) {
        this.clientService = clientService;
    }

    @PostMapping
    ClientDto addClient(@RequestBody ClientDto clientDto) throws FunctionalException {
        return this.clientService.createOrUpdateClient(clientDto, null);
    }

    @PutMapping(path = "/{id}")
    ClientDto updateClient(@PathVariable String id, @RequestBody ClientDto clientDto) throws FunctionalException {
        return this.clientService.createOrUpdateClient(clientDto, id);
    }
}

当我发布一个有父母或没有父母的新客户时,没关系,一切顺利。

但是当我尝试更新(通过在 clientResource 中使用 put)以删除子实体和父实体之间的关系时,我有一个像这样的休眠异常:

HibernateException: identifier of an instance of xxxx.model.Client was altered from 7fa60bf2-e176-4b96-aae4-cbfa6461cb0e to null

我阅读了很多帖子,但我的 ID 生成良好,我只是不明白为什么我不能将 null 设置为 parent 来定义没有父母的孩子。我还尝试将孩子添加为 OneToMany,但不明白这样做的必要性。

非常感谢您的回复! :) 抱歉英语不好。

【问题讨论】:

    标签: java spring hibernate


    【解决方案1】:

    错误消息表明实体Client 的id 值正在更改为null。这很可能发生在这一行:

    this.clientMapper.updateClientFromDto(clientDto, client);
    

    在对现有对象进行更新时,不应更改其 ID(请参阅this)。要么您需要确保 clientDto 没有空 id 值,要么您需要从 clientDto 中排除设置 client 的 id。

    另一个注意事项:如果您使用生成的标识符值 (@GeneratedValue(generator = "UUID")),那么最好删除 id 字段上的设置器,因为该值将自动生成:

    @Setter(AccessLevel.NONE)
    private String id;
    

    【讨论】:

    • 感谢您的回复我只是想删除父子之间的关系,所以我在 clientParent 中设置了 null。我想要实现的是通过将 null 设置为父属性来删除子与父之间的关系,而不仅仅是更改实体的 id。也许这不是这样做的方法?
    • @notSoEasy 我不认为将 clientParent 设置为 null 是问题所在。问题似乎是因为您将孩子的id 属性(不是clientParent)设置为null。
    • 我已经启动调试验证并且我在子客户端上的 Id 不为空,clientParent 为空,例如这是要保存的客户端导致错误 client = {Client@10395} name = "non équipe de lui en fait" 地址 = {Address@10399} headOffice = false clientParent = null id = "e17ee791-1de3-4d8e-8fa5-2f9303815506" createdDate = {Timestamp@10401} "2021-02-22 17: 35:35.02" modifiedDate = {Timestamp@10402} "2021-02-22 17:36:25.057"