Skip to main content
 首页 » 编程设计

java中为什么@JoinColumns 的顺序很重要

2025年12月25日52EasonJim

我发现 Hibernate 有一些奇怪的行为。我在两个使用嵌入式复合主键的实体之间有一对多关系。 (是的,我知道数据设计很糟糕,但这是我必须使用的模式)

@Entity 
@Table(name = "T_PLACE") 
public class Place { 
    @EmbeddedId 
    private PlacePK id; 
 
    @OneToMany(mappedBy = "place") 
    private List<Mode> modes; 
 
    // getters and setters 
} 

@Embeddable 
public class PlacePK implements Serializable { 
    @Column(name = "COMPANY") 
    private String company; 
 
    @Column(name = "AREA") 
    private String area; 
 
    @Column(name = "COLOR") 
    private String color; 
 
    // getters and setters 
} 

@Entity 
@Table(name = "T_MODE") 
public class Mode { 
 
    @EmbeddedId 
    private ModePK id; 
 
    @ManyToOne 
    @JoinColumns({ 
            @JoinColumn(name = "COMPANY", insertable = false, updatable = false), 
            @JoinColumn(name = "AREA", insertable = false, updatable = false), 
            @JoinColumn(name = "COLOR", insertable = false, updatable = false), 
    }) 
    private Place place; 
 
    private String function; 
 
    // getters and setters 
 } 

@Embeddable 
public class ModePK implements Serializable { 
    @Column(name = "COMPANY") 
    private String company; 
 
    @Column(name = "AREA") 
    private String area; 
 
    @Column(name = "COLOR") 
    private String color; 
 
    @Column(name = "MODE_ID") 
    private String color; 
 
    // getters and setters 
} 

但是在查询某个地点的模式时,生成的 HQL 最终会像这样排序

where 
        company=?  
        and color=?  
        and area=? 

最终将区域绑定(bind)到第二个 ? 并将颜色绑定(bind)到第三个 ?

除非我更改 @JoinColumn 的顺序以将颜色放在区域之前,否则它不起作用。

@JoinColumns({ 
    @JoinColumn(name = "COMPANY", insertable = false, updatable = false), 
    @JoinColumn(name = "COLOR", insertable = false, updatable = false), 
    @JoinColumn(name = "AREA", insertable = false, updatable = false), 
}) 

所以我的问题是,是什么导致了这种行为?什么决定了 HQL 中 where 子句的顺序?这不是任何问题,因为我已经弄清楚如何让它工作,但我想理解它。

我正在使用 spring-boot-starter-data-jpa:1.5.10-RELEASE,它使用 Hibernate 5。


编辑

这是我生成 HQL 的方式

@Repository 
public interface PlaceRepository extends JpaRepository<Place, PlacePK> {} 

然后在测试中:

PlacePK placePK = new PlacePK(); 
placePK.setCompany("Acme"); 
placePK.setArea("XYZ"); 
place.PK.setColor("Blue"); 
Place place = placeRepository.findOne(placePK); 
List<Mode> modes = place.getModes(); // ends up being an empty PersistBag until I switch the order of the @JoinColumns 
assertNotNull(modes); 

请您参考如下方法:

该顺序很重要,因为 Hibernate 根据此顺序构建连接条件。 Hibernate 不知道如何将特定列相互映射(尽管它可以通过命名比较来实现,但是......)。因此,它只需按照您指定的 ID 列的顺序放置它们即可。

要查看差异排序的作用,请打开生成的 SQL 查询的日志记录。您将看到,如果您的顺序与 ID 键的顺序不一致,您的获取查询可能会出现类似

...join PlacePK pk ON pk.COMPANY = m.AREA*emphasized text*