使用JPA+Hibernate时MySQL int映射Java Long字段返回Null问题
问题分析与解决方案
嘿,我来帮你排查这个主键字段返回null的问题!结合你的代码和场景,主要问题出在复合主键的映射规范、Java与数据库类型匹配以及Lombok注解的小细节上,我逐一给你拆解:
1. 复合主键的正确配置方式
JPA中使用复合主键时,直接给两个字段加@Id是不完整的,必须通过@IdClass或@EmbeddedId来明确主键的组合规则,否则Hibernate无法正确识别和映射复合主键。
方式一:使用@IdClass
- 先创建一个主键类,需要满足:实现
Serializable接口、重写equals()和hashCode()、字段名/类型与实体类主键完全一致
// 复合主键类 public class DummyId implements Serializable { private Integer testId; private Integer otherTestId; // 手动实现equals和hashCode,或用Lombok的@Data注解 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DummyId dummyId = (DummyId) o; return Objects.equals(testId, dummyId.testId) && Objects.equals(otherTestId, dummyId.otherTestId); } @Override public int hashCode() { return Objects.hash(testId, otherTestId); } }
- 修改实体类,添加
@IdClass关联主键类:
@Entity @IdClass(DummyId.class) // 关联主键类 @EqualsAndHashCode(of = {"testId", "otherTestId"}) // 注意这里用实体类字段名,不是数据库字段名 @Table(name = "test_table") @Data class Dummy { @Id @Column(name = "test_id", nullable = false) private Integer testId; // 后面会解释为什么改成Integer @Id @Column(name = "other_test_id", nullable = false) private Integer otherTestId; }
方式二:使用@EmbeddedId
- 创建嵌入式主键类,用
@Embeddable标注:
@Embeddable public class DummyId implements Serializable { @Column(name = "test_id", nullable = false) private Integer testId; @Column(name = "other_test_id", nullable = false) private Integer otherTestId; // equals、hashCode方法或@Data注解 }
- 实体类中用
@EmbeddedId替代两个独立的@Id:
@Entity @EqualsAndHashCode(of = {"dummyId"}) @Table(name = "test_table") @Data class Dummy { @EmbeddedId private DummyId dummyId; }
2. Java类型与数据库类型的匹配问题
你的MySQL字段是int(11),对应的Java类型应该是Integer而非Long——Long对应MySQL的bigint类型。类型不匹配会导致Hibernate在映射时无法正确读取字段值,最终返回null。这是你当前问题的核心原因之一,一定要把Long改成Integer。
3. Lombok注解的小错误
你在@EqualsAndHashCode(of = {"test_id", "other_test_id"})里写的是数据库字段名,但这里需要用实体类的字段名testId和otherTestId,否则Lombok生成的方法会找不到对应字段,可能影响实体的比较逻辑,间接干扰查询结果。
总结修复步骤
- 选择
@IdClass或@EmbeddedId规范配置复合主键 - 将实体类和主键类的字段类型从
Long改为Integer,匹配MySQL的int(11) - 修正
@EqualsAndHashCode的参数为实体类的字段名
按照以上步骤调整后,重新运行查询,应该就能正常获取到两个主键字段的值了。
内容的提问来源于stack exchange,提问作者Vivin
相关产品推荐
相关产品推荐

