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

在getId()方法添加@Id注解导致自增ID列抛出异常的原因

为何在getId()方法上添加@Id注解时,自增ID列会抛出异常?

报错信息

Type Exception Report

Message Converting `org.hibernate.id.IdentifierGenerationException` to JPA `PersistenceException` : ids for this class must be manually assigned before calling save(): models.User

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

jakarta.persistence.PersistenceException: Converting `org.hibernate.id.IdentifierGenerationException` to JPA `PersistenceException` : ids for this class must be manually assigned before calling save(): models.User
    org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:165)
    org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:175)
    org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:182)
    org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:741)
    org.hibernate.internal.SessionImpl.persist(SessionImpl.java:719)
    servlets.Authentication.doGet(Authentication.java:30)
    jakarta.servlet.http.HttpServlet.service(HttpServlet.java:668)
    jakarta.servlet.http.HttpServlet.service(HttpServlet.java:777)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Root Cause

org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): models.User
    org.hibernate.id.Assigned.generate(Assigned.java:33)
    org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:114)
    org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:184)
    org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:129)
    org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:53)
    org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)
    org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:735)
    org.hibernate.internal.SessionImpl.persist(SessionImpl.java:719)
    servlets.Authentication.doGet(Authentication.java:30)
    jakarta.servlet.http.HttpServlet.service(HttpServlet.java:668)
    jakarta.servlet.http.HttpServlet.service(HttpServlet.java:777)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)

实体类代码

package models;

import jakarta.persistence.*;

import java.sql.Date;

@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private int id;
    @Column(name = "nome", nullable = false)
    private String nome;
    @Column(name = "cognome", nullable = false)
    private String cognome;
    @Column(name = "mail", nullable = false)
    private String mail;
    @Column(name = "password", nullable = false)
    private String password;
    @Column(name = "token", nullable = true)
    private String token;
    @Column(name = "dataCreazioneToken", nullable = true)
    private Date dataCreazioneToken;

    public User() {}

    public User(String nome, String cognome, String mail, String password) {
        this.nome = nome;
        this.cognome = cognome;
        this.mail = mail;
        this.password = password;
    }

    public Date getDataCreazioneToken() {
        return dataCreazioneToken;
    }

    public void setDataCreazioneToken(Date creazioneToken) {
        this.dataCreazioneToken = creazioneToken;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getCognome() {
        return cognome;
    }

    public void setCognome(String cognome) {
        this.cognome = cognome;
    }

    public String getMail() {
        return mail;
    }

    public void setMail(String mail) {
        this.mail = mail;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setId (int id) {
        this.id = id;
    }

    @Id
    public int getId() {
        return id;
    }
}

问题现象

移除getId()方法上的@Id注解后,异常不再出现,ID可正常自动生成,无法理解该现象的原因。


原因解析

JPA(以Hibernate为实现)有两种属性访问策略:字段访问和方法访问,单个实体类只能二选一,不能混用。

  1. 你在id字段上添加了@Id和@GeneratedValue(strategy = GenerationType.IDENTITY),这属于字段访问策略,明确告诉Hibernate该字段是主键,且由数据库自动生成值。
  2. 但你又在getId()方法上重复添加@Id注解,这会让Hibernate优先采用方法访问策略。此时方法上的@Id没有搭配@GeneratedValue,Hibernate会默认使用Assigned生成策略——要求开发者手动为ID赋值,否则就抛出ids for this class must be manually assigned before calling save()异常。
  3. 移除方法上的@Id后,Hibernate回到字段访问策略,遵循字段上的@GeneratedValue配置,让数据库自动生成ID,因此异常消失。

解决方案

保持实体类的访问策略一致:要么所有注解都加在字段上,要么都加在对应的getter方法上。比如保留字段上的@Id和@GeneratedValue,删除方法上的@Id即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 03:45:30