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

使用@ManyToOne与复合主键的JPA实体保存时出现多余参数问题

Hibernate 5.6复合主键关联@ManyToOne保存时参数越界问题

问题场景

使用Hibernate 5.6的旧版Spring Boot项目中,定义了如下实体类:

@Entity 
class A { 
    Long getId(); 
    // 其他字段及实现
}

@Entity 
class B { 
    Long getId(); 
    // 其他字段及实现
}

@Entity
@IdClass(ABPK.class)
@Data
class AB {
    @Id
    @Column(name="a_id", insertable=false, updatable=false)
    private Long aId;
    @Id
    @Column(name="b_id", insertable=false, updatable=false)
    private Long bId;
    
    @ManyToOne
    @JoinColumn(name="a_id")
    private A a;
    
    @ManyToOne
    @JoinColumn(name="b_id")
    private B b;
    
    public AB() { }
    public AB(A a, B b) {
        this.a = a;
        this.aId = a.getId();
        this.b = b;
        this.bId = b.getId();
    }
}

@Data
class ABPK implements Serializable {
    Long aId;
    Long bId;
}

执行保存操作时:

var a = new A("a");
var b = new B("b");
var ab = new AB(a,b);
abDao.saveAndFlush(ab);

抛出错误:

Caused by: java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).

日志中生成的INSERT语句看似正确:

Hibernate: insert into ab (a_id, b_id) values (?, ?)

调试发现映射时多传递了参数,实际传递了AB类型、A类型、B类型对应的值,而预期仅需两个字段参数。

解决方案

问题根源在于**@Id字段和@ManyToOne的关联字段重复映射了数据库中的同一列**,Hibernate在处理时重复绑定了参数。正确的做法是使用@MapsId注解将@ManyToOne关联与@Id字段绑定,让Hibernate知道两者对应同一列,避免重复处理:

修改AB实体类如下:

@Entity
@IdClass(ABPK.class)
@Data
class AB {
    @Id
    private Long aId;
    @Id
    private Long bId;
    
    @ManyToOne
    @MapsId("aId") // 将该关联与aId主键字段绑定
    @JoinColumn(name="a_id")
    private A a;
    
    @ManyToOne
    @MapsId("bId") // 将该关联与bId主键字段绑定
    @JoinColumn(name="b_id")
    private B b;
    
    public AB() { }
    public AB(A a, B b) {
        this.a = a;
        this.b = b;
        // 无需手动设置aId和bId,Hibernate会通过关联对象自动赋值
    }
}

说明

  • 去掉@Id字段上的insertable=false, updatable=false,因为@MapsId已经明确了主键字段由关联对象维护
  • @MapsId("aId")表示将@ManyToOne关联的A对象的主键值,映射到当前实体的aId主键字段,对应数据库的a_id列
  • 构造方法中无需手动设置aId和bId,Hibernate会自动从关联的A、B对象中获取主键值赋值给主键字段

这样修改后,Hibernate在生成INSERT语句时只会绑定两个参数,不会出现参数索引越界的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 23:53:13