如何为数据库分区表定义JPA实体,解决IDENTITY字段插入报错问题
问题原因
JPA规范仅支持将@GeneratedValue注解标注在实体类直接声明的@Id字段上,放在@Embeddable复合主键类内部的字段上不会被识别,因此你之前的配置没有生效,Hibernate仍然把entity_key_map_id当做普通主键字段处理,插入时传入null值触发了数据库报错。
解决方案
方案1:使用JPA标准@IdClass实现复合主键(推荐,无框架依赖)
- 改造主键类
EntityKeyMapPK,移除所有JPA注解,只保留基础字段、无参构造、equals/hashCode重写、getter/setter:
import java.io.Serializable; public class EntityKeyMapPK implements Serializable { private Long entityKeyMapId; private EntityType systemEntityAlias; public EntityKeyMapPK() {} // 重写equals和hashCode,必须基于两个主键字段判断 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; EntityKeyMapPK that = (EntityKeyMapPK) o; return entityKeyMapId.equals(that.entityKeyMapId) && systemEntityAlias.equals(that.systemEntityAlias); } @Override public int hashCode() { int result = entityKeyMapId.hashCode(); result = 31 * result + systemEntityAlias.hashCode(); return result; } // getter和setter public Long getEntityKeyMapId() { return entityKeyMapId; } public void setEntityKeyMapId(Long entityKeyMapId) { this.entityKeyMapId = entityKeyMapId; } public EntityType getSystemEntityAlias() { return systemEntityAlias; } public void setSystemEntityAlias(EntityType systemEntityAlias) { this.systemEntityAlias = systemEntityAlias; } }
- 改造实体类,使用
@IdClass绑定主键类,将两个主键字段直接声明在实体类中,给自增字段标注@GeneratedValue:
import javax.persistence.*; @Entity @Table(name = "entity_key_map", schema = "integration") @IdClass(EntityKeyMapPK.class) public class EntityKeyMap { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "entity_key_map_id", nullable = false) private Long entityKeyMapId; @Id @Column(name = "system_entity_alias", nullable = false) private EntityType systemEntityAlias; // 以下原有业务字段保持不变,无需修改 @Column(name = "business_entity_alias", nullable = false, length = 5) @JsonProperty("businessEntityAlias") private EntityType businessEntityAlias; @Column(name = "business_key_1", nullable = false) @JsonProperty("businessKey1") private String businessKey1; // 其余business_key_2~5、system_alias、system_key_1~5的原有注解和定义全部保留 // ... 省略原有业务字段定义 // 所有字段的getter和setter }
方案2:保留@EmbeddedId(依赖Hibernate专有特性)
如果不想调整现有@EmbeddedId的结构,可以用Hibernate提供的@Generated注解标注自增字段,告诉Hibernate该字段由数据库插入时生成:
- 改造主键类
EntityKeyMapPK:
import org.hibernate.annotations.Generated; import org.hibernate.annotations.GenerationTime; import javax.persistence.Column; import javax.persistence.Embeddable; import java.io.Serializable; @Embeddable public class EntityKeyMapPK implements Serializable { @Generated(GenerationTime.INSERT) // 新增:标注该字段插入时由数据库生成 @Column(name = "entity_key_map_id", nullable = false, insertable = false, updatable = false) private Long entityKeyMapId; @Column(name = "system_entity_alias", nullable = false) private EntityType systemEntityAlias; // 原有equals、hashCode、getter、setter保持不变 // ... }
- 实体类无需修改,保持原有
@EmbeddedId的定义即可。
插入操作注意事项
两种方案插入数据时都不需要给entityKeyMapId赋值,只需要填充systemEntityAlias和其他业务字段,持久化完成后Hibernate会自动将数据库生成的自增ID回写到实体对象中,生成的INSERT语句不会携带entity_key_map_id字段,和你手动编写的SQL效果一致。
内容的提问来源于stack exchange,提问作者suitej
相关产品推荐
相关产品推荐

