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

Hibernate 6迁移后HQL左连接WHERE子句SQL转换错误问题

Hibernate 5.4.30.Final 迁移至 6.2.0.Final 后HQL查询SQL转换异常

将Hibernate从5.4.30.Final版本升级到6.2.0.Final后,部分HQL查询的SQL转换出现错误,导致查询结果不符合预期。以下是最小复现场景:

实体类定义(省略getter/setter)

@Entity
public class Author {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
}

@Entity
public class PublishingHouse {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
}

Book实体包含指向Author和PublishingHouse的多对一关联:

@Entity
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String title;
    
    @ManyToOne
    private Author author;
    
    @ManyToOne
    private PublishingHouse publishingHouse;
}

测试代码与异常结果

在Main方法中插入测试数据后,执行HQL查询所有作者为Stephen King或出版社为Simon & Schuster的书籍:

public static void main(String[] args) {
    Transaction transaction = null;
    PublishingHouse phSimonSchuster = null;
    Author stephenKing = null;
    
    try (Session session = HibernateUtil.getSessionFactory().openSession()) {
        transaction = session.beginTransaction();
        
        // 插入出版社数据
        phSimonSchuster = new PublishingHouse();
        phSimonSchuster.setName("Simon & Schuster");
        session.persist(phSimonSchuster);
        
        var phHarperCollins = new PublishingHouse();
        phHarperCollins.setName("HarperCollins");
        session.persist(phHarperCollins);
        
        // 插入作者数据
        stephenKing = new Author();
        stephenKing.setName("Stephen King");
        session.persist(stephenKing);
        
        var hpLovecraft = new Author();
        hpLovecraft.setName("Howard Phillips Lovecraft");
        session.persist(hpLovecraft);
        
        // 插入书籍数据
        var bShining = new Book();
        bShining.setTitle("Shining");
        bShining.setAuthor(stephenKing);
        bShining.setPublishingHouse(phSimonSchuster);
        session.persist(bShining);
        
        var bColorOutOfSpace = new Book();
        bColorOutOfSpace.setTitle("The Colour Out of Space");
        bColorOutOfSpace.setAuthor(hpLovecraft);
        bColorOutOfSpace.setPublishingHouse(phHarperCollins);
        session.persist(bColorOutOfSpace);
    
        transaction.commit();
    }
    
    try (Session session = HibernateUtil.getSessionFactory().openSession()) {
        var hql = "SELECT book "
                + "FROM Book book "
                + "   LEFT JOIN book.author author "
                + "        WITH author.id = :stephenKingId "
                + "   LEFT JOIN book.publishingHouse publishingHouse "
                + "        WITH publishingHouse.id = :simonSchusterId "
                + "WHERE author IS NOT NULL OR publishingHouse IS NOT NULL ";
        
        List<Book> books = session.createQuery(hql, Book.class)
                .setParameter("stephenKingId", stephenKing.getId())
                .setParameter("simonSchusterId", phSimonSchuster.getId())
                .list();
        books.forEach(b -> {
            System.out.println("Book found: " + b.getTitle());
        });
    }
}

实际输出结果

Book found: Shining
Book found: The Colour Out of Space

根据插入的数据逻辑,《The Colour Out of Space》的作者并非Stephen King,出版社也不是Simon & Schuster,本不应被查询出来。

错误SQL分析

Hibernate将上述HQL转换为了错误的SQL:

SELECT b1_0.id,
       b1_0.author_id,
       b1_0.publishinghouse_id,
       b1_0.title
FROM   book b1_0
       LEFT JOIN author a1_0
              ON a1_0.id = b1_0.author_id
             AND b1_0.author_id = ?
       LEFT JOIN publishinghouse p1_0
              ON p1_0.id = b1_0.publishinghouse_id
             AND b1_0.publishinghouse_id = ?
WHERE  b1_0.author_id IS NOT NULL
   OR b1_0.publishinghouse_id IS NOT NULL 

错误点:

  • WHERE条件判断的是Book实体的author_id和publishinghouse_id是否非空,而非左连接后的关联实体是否存在
  • WITH子句的条件被错误转换为判断Book的外键值,而非关联实体的ID

正确SQL示例

符合预期的SQL应该是:

SELECT b1_0.id,
       b1_0.author_id,
       b1_0.publishinghouse_id,
       b1_0.title
FROM   book b1_0
       LEFT JOIN author a1_0
              ON a1_0.id = b1_0.author_id
             AND a1_0.id = ?
       LEFT JOIN publishinghouse p1_0
              ON p1_0.id = b1_0.publishinghouse_id
             AND p1_0.id = ?
WHERE a1_0.id IS NOT NULL OR p1_0.id IS NOT NULL 

该SQL可以正确筛选出作者为Stephen King或出版社为Simon & Schuster的书籍。此问题在Hibernate 6.0以下版本不会出现。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 16:04:55