Hibernate复合主键含日期类型插入报错IdentifierGenerationException求助
嘿,我来帮你搞定这个Hibernate日期主键的问题!结合你遇到的报错和代码情况,我分两种场景给你讲清楚解决方案:
如果你的实体只有Date类型的主键,核心注意点是:Hibernate默认的主键生成策略不支持自动生成Date类型主键,所以不能加@GeneratedValue(除非你自定义生成器),得手动设置主键值,同时明确指定日期的存储类型:
@Entity public class SingleDateKeyEntity { @Id @Temporal(TemporalType.TIMESTAMP) // 按需选TIMESTAMP/DATE/TIME private Date id; // 其他字段、getter/setter }
插入数据时,你需要自己给id字段赋值(比如用当前时间),然后再调用persist方法保存。
你遇到的报错org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.util.Date,本质是给Date类型的主键字段加了@GeneratedValue(strategy = GenerationType.AUTO)——Hibernate的AUTO策略只支持数值型(Long/Integer)或特定生成器生成的字符串,完全不兼容Date类型。而且复合主键的配置也有特定规范,具体步骤如下:
步骤1:定义复合主键类
复合主键必须是一个实现Serializable的类,还要重写equals()和hashCode(),示例如下(根据你实际的前两个主键类型调整):
import java.io.Serializable; import java.util.Date; import java.util.Objects; public class PartyContactMechPK implements Serializable { // 对应你实体里的第一个Long主键 private Long firstId; // 假设第二个主键是String,根据你的实际情况修改类型 private String secondId; // Date类型的第三个主键 private Date thirdId; // 必须有无参构造器 public PartyContactMechPK() {} // 带参构造器方便创建对象 public PartyContactMechPK(Long firstId, String secondId, Date thirdId) { this.firstId = firstId; this.secondId = secondId; this.thirdId = thirdId; } // 生成getter和setter方法 // ... // 重写equals和hashCode,用于Hibernate判断主键唯一性 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PartyContactMechPK that = (PartyContactMechPK) o; return Objects.equals(firstId, that.firstId) && Objects.equals(secondId, that.secondId) && Objects.equals(thirdId, that.thirdId); } @Override public int hashCode() { return Objects.hash(firstId, secondId, thirdId); } }
步骤2:修改实体类
用@EmbeddedId关联刚才定义的复合主键类,去掉原来单个主键字段上的@GeneratedValue注解:
import javax.persistence.*; import java.util.List; @Entity public class PartyContactMech extends BaseEntity { @EmbeddedId private PartyContactMechPK pk; // 你的其他字段,比如关联的List @OneToMany(mappedBy = "partyContactMech") private List<YourRelatedEntity> relatedEntities; // 生成getter和setter方法 // ... }
步骤3:插入数据的正确姿势
插入时需要手动创建复合主键对象,给三个主键字段都赋值(包括Date类型的),再关联到实体上:
// 创建复合主键对象,第三个参数传你需要的Date值(比如当前时间) PartyContactMechPK pk = new PartyContactMechPK(1001L, "CONTACT_MECH_001", new Date()); // 创建实体并绑定主键 PartyContactMech entity = new PartyContactMech(); entity.setPk(pk); // 给其他字段赋值 // ... // 保存到数据库 entityManager.persist(entity);
可选:自动生成Date类型的主键值
如果不想手动设置Date,想让Hibernate自动生成(比如用当前时间戳),可以自定义一个主键生成器:
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.IdentifierGenerator; import java.util.Date; public class DateIdGenerator implements IdentifierGenerator { @Override public Object generate(SharedSessionContractImplementor session, Object object) { // 返回当前时间作为主键值 return new Date(); } }
然后在复合主键类的Date字段上指定这个生成器:
public class PartyContactMechPK implements Serializable { // ...其他字段 @GeneratedValue(generator = "date-id-generator") @GenericGenerator(name = "date-id-generator", strategy = "com.yourpackage.DateIdGenerator") private Date thirdId; // ... }
⚠️ 注意:用自动生成的Date作为复合主键的一部分,要确保三个主键的组合唯一,避免出现同一时间插入相同前两个主键的情况,否则会触发唯一约束报错。
你之前的错误就是给Date类型的主键加了@GeneratedValue(strategy = GenerationType.AUTO),Hibernate没法用数值型的生成逻辑去生成Date类型的主键,所以直接抛了异常——只要去掉这个注解,按照复合主键的规范配置,再手动赋值或者用自定义生成器,问题就解决啦!
内容的提问来源于stack exchange,提问作者M.A.M

