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

Hibernate JOINED继承下@Version字段插入NULL报错问题咨询

解决Hibernate JOINED继承下@Version字段的NULL插入问题

嘿,我来帮你理清这个问题的核心原因和解决方案:

在你使用InheritanceType.JOINED继承策略时,结合@MappedSuperclass的字段继承逻辑,Hibernate的处理方式其实有明确规则:

  • @MappedSuperclass里的字段(包括你的@Version)会被**第一个实体子类(也就是Credential)**继承,并且映射到根实体对应的表(credentials)中。
  • 而UserIdCredentials作为JOINED继承的子类,它的表只需要存储自己独有的业务字段,加上关联根表的主键外键就行,完全不需要重复存储来自BaseEntity的version、created_at、updated_at这些字段。

你遇到的SQLServerException,本质就是因为子类表(userid_credentials)里多了这些重复字段,但Hibernate在插入UserIdCredentials实体时,只会把继承来的字段值写入根表credentials,根本不会管子类表的这些重复字段,结果就导致子类表的version被插入NULL(而你又设置了该字段非空),直接触发报错。


正确的处理方式

1. 移除子类表中的重复字段

你最开始移除userid_credentials表中version、created_at、updated_at字段的做法,其实是完全正确的:

  • 只保留子类自身的字段(username、passwordEncoded)和关联根表的主键字段(id)即可。
  • 这样Hibernate操作UserIdCredentials时,会把继承自BaseEntity的字段都写入credentials表,子类表只处理自己的业务字段,自然不会再有NULL插入的问题。

2. 为什么不需要子类表的version字段?

在JOINED继承策略下,Hibernate的乐观锁默认是基于根实体的version字段来实现的。当你更新UserIdCredentials实体时,Hibernate会自动递增credentials表中的version值,以此来做乐观锁的冲突检测,完全不需要子类表单独维护version。


特殊场景:如果确实需要子类表独立维护version

如果你有非常特殊的业务需求,必须让子类表也有自己独立的version字段(这种场景真的很少见),可以这么做:

  • 在UserIdCredentials中重新定义@Version字段,覆盖父类的版本属性:
@Entity 
@Table(name = "userid_credentials", uniqueConstraints = {@UniqueConstraint(columnNames = "username")})
@PrimaryKeyJoinColumn(name = "id")
public class UserIdCredentials extends Credential {
    // ... 原有字段
    
    @Override
    @Version
    private long version = 1;
}
  • 同时确保userid_credentials表的version字段存在且非空。
  • 这种情况下,Hibernate会分别维护根表和子类表的version字段,更新实体时两个字段都会递增。但我必须提醒你,这种做法会增加乐观锁的复杂度,除非有明确的业务必要性,否则不推荐使用。

总的来说,你一开始移除子类表重复字段的处理是完全符合Hibernate设计逻辑的,根本不需要让两张表的version都更新,根表的version已经足够完成乐观锁的控制了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 06:32:32