Spring Data JPA 3.0.2中@OneToMany多关联列绑定顺序错误求助
Spring Boot JPA 3.0.2升级后,@OneToMany注解搭配多@JoinColumn(REF_NO、SEQ_NO)时出现参数绑定顺序颠倒问题:ref_no的值被绑定到seq_no字段,seq_no的值被绑定到ref_no字段。同一实体类中使用相同多列关联配置的@OneToOne注解则无此问题,且Spring Boot 2.7.2版本下@OneToMany绑定正常。
代码与现象对比
异常的@OneToMany实现
@OneToMany(fetch = EAGER) @JoinColumns({ @JoinColumn(name = "REF_NO", referencedColumnName = "REF_NO"), @JoinColumn(name = "SEQ_NO", referencedColumnName = "SEQ_NO") }) public Set<InProcessPartyEntity> getParties() { return parties; }
生成的SQL条件为(p1_0.seq_no,p1_0.ref_no) in((?,?)),参数1传入E313100005323221237(应为ref_no的值)、参数2传入001(应为seq_no的值),列与参数顺序完全颠倒。
正常的@OneToOne实现
@OneToOne(fetch = EAGER) @JoinColumns({ @JoinColumn(name = "REF_NO", referencedColumnName = "REF_NO"), @JoinColumn(name = "SEQ_NO", referencedColumnName = "SEQ_NO") }) public InProcessWorkUnitEntity getWorkUnit() { return workUnit; }
生成的SQL条件为(i1_0.ref_no,i1_0.seq_no) in((?,?)),参数绑定顺序与列顺序匹配,逻辑正确。
升级Spring Boot至3.1.x及以上版本
Spring Boot 3.0.x属于早期适配Hibernate 6.x的版本,存在部分兼容性bug。后续发布的3.1.x及更高版本已修复大量JPA关联逻辑问题,升级后大概率解决参数绑定顺序颠倒的问题。显式指定关联列的绑定顺序
Hibernate 6.x处理集合关联时,可能会按列名字典序重新排序关联列,导致与@JoinColumns声明顺序不一致。可以通过以下方式强制指定顺序:- 调整
@JoinColumn的声明顺序,使其与数据库表中联合键的物理顺序一致; - 使用
@Where注解手动编写关联条件,绕过框架自动生成的SQL逻辑:@OneToMany(fetch = EAGER) @JoinColumns({ @JoinColumn(name = "REF_NO", referencedColumnName = "REF_NO"), @JoinColumn(name = "SEQ_NO", referencedColumnName = "SEQ_NO") }) @Where(clause = "REF_NO = :refNo AND SEQ_NO = :seqNo") public Set<InProcessPartyEntity> getParties() { return parties; }
- 调整
改用手动查询替代自动关联
如果上述方案无效,可暂时移除@OneToMany注解,在Repository中编写自定义SQL查询关联数据:@Repository public interface InProcessPartyRepository extends JpaRepository<InProcessPartyEntity, Long> { @Query("SELECT p FROM InProcessPartyEntity p WHERE p.refNo = :refNo AND p.seqNo = :seqNo") Set<InProcessPartyEntity> findByRefNoAndSeqNo(@Param("refNo") String refNo, @Param("seqNo") String seqNo); }在主实体类中通过调用该Repository方法获取关联数据,避免框架自动生成错误的绑定逻辑。
调试Hibernate生成逻辑
添加以下配置到application.properties,查看Hibernate解析注解的详细日志,定位问题根源:spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.type=trace通过日志确认Hibernate对
@JoinColumns的排序逻辑,必要时可针对性调整注解配置。
内容的提问来源于stack exchange,提问作者Akshaya

