Hibernate复合主键外键重叠保存时bank_id非空约束报错如何解决
问题根因
你触发异常的核心原因是BonusEntity的关联注解配置错误:
- 你给关联
AccountEntity的三个@JoinColumn全部设置了insertable = false, updatable = false,意味着Hibernate在插入数据时不会处理这三个外键字段的写入 - 其中
cluster_id属于BonusEntity的复合主键,所以插入时会自动赋值,但bank_id、user_id没有任何对应字段负责写入,自然就是NULL,触发数据库非空约束
解决方案
你只需要调整关联注解的配置,仅保留主键重叠字段cluster_id的insertable = false, updatable = false配置,剩下两个外键字段放开写入权限即可,Hibernate会自动从关联的AccountEntity主键中提取对应值写入表中:
调整后的BonusEntity代码示例:
@Entity @Table(name = "cbonus") public class BonusEntity { @EmbeddedId @AttributeOverride(name = "id", column = @Column(name = "id")) @AttributeOverride(name = "clusterId", column = @Column(name = "cluster_id")) private BonusId bonusId; private boolean released; @ManyToOne(targetEntity = AccountEntity.class, optional = false, fetch = FetchType.LAZY) @JoinColumn(name = "cluster_id", referencedColumnName = "cluster_id", insertable = false, updatable = false) // 去掉bank_id、user_id对应的insertable、updatable禁用配置 @JoinColumn(name = "bank_id", referencedColumnName = "bank_id") @JoinColumn(name = "user_id", referencedColumnName = "user_id") private AccountEntity account; }
补充注意事项
如果你的业务场景需要单独访问bank_id、user_id字段不需要加载整个AccountEntity,也可以在BonusEntity中显式定义这两个字段,再调整关联注解的配置关联到这两个字段即可:
@Entity @Table(name = "cbonus") public class BonusEntity { @EmbeddedId @AttributeOverride(name = "id", column = @Column(name = "id")) @AttributeOverride(name = "clusterId", column = @Column(name = "cluster_id")) private BonusId bonusId; @Column(name = "bank_id", nullable = false) private Long bankId; @Column(name = "user_id", nullable = false) private String userId; private boolean released; @ManyToOne(targetEntity = AccountEntity.class, optional = false, fetch = FetchType.LAZY) @JoinColumn(name = "cluster_id", referencedColumnName = "cluster_id", insertable = false, updatable = false) @JoinColumn(name = "bank_id", referencedColumnName = "bank_id", insertable = false, updatable = false) @JoinColumn(name = "user_id", referencedColumnName = "user_id", insertable = false, updatable = false) private AccountEntity account; // 自定义setAccount方法自动同步bankId、userId字段 public void setAccount(AccountEntity account) { this.account = account; this.bankId = account.getAccountId().getBankId(); this.userId = account.getAccountId().getUserId(); } }
使用这种方案时,保存BonusEntity前调用setAccount方法即可自动完成字段同步,不需要手动赋值两个外键字段。
内容的提问来源于stack exchange,提问作者Vasiliy Tungusov
相关产品推荐
相关产品推荐

