在使用遗留的Criteria API时,如何阻止Hibernate将关联加入到SQL SELECT语句中?

后端开发 2026-07-09

在使用Hibernate的旧版Criteria API,对一个 many-to-one 关联进行过滤,但只检索基实体类型时,生成的SQL仍然会把该关联的所有列加入到SELECT中吗?如下示例所示?

Entities

class User
{
    long id;
    boolean active;
    Address address;
}

class Address
{
    long id;
    String streetNum;
    String street;
    String country;
}

Criteria with Alias

Criteria criteria = session.createCriteria(User.class, "u");
criteria.createAlias("u.address", "a");
criteria.add(Restrictions.eq("a.streetNum", "15"));

final List<User> users = criteria.list();

SQL generated

SELECT 
    u.id,
    u.active,
    a.id,
    a.streetNum,
    a.street,
    a.country
FROM
    user AS u
    JOIN address AS a ON u.addressID = a.id
WHERE
    a.streetNum = 15

SQL assumed

SELECT 
    u.id,
    u.active
FROM
    user AS u
    JOIN address AS a ON u.addressID = a.id
WHERE
    a.streetNum = 15

Performance problems

这会导致生成的SQL包含所有被连接的别名表的所有列,在列数众多、需要对多处关联进行筛选并进行分页的场景下,性能将受到极大影响。

该查询并不需要检索关联的列。

NHibernate

在C#的 NHibernate中,似乎他们有 Projections.rootEntity()(我猜是为了这种情况),但在Java版 Hibernate 5.5.7中没有。

解决方案

这是 @ManyToOne与 @OneToOne关系的默认急加载(EAGER fetching)行为。Criteria API默认会遵循映射层级的抓取配置。但在需要时,是否可以通过诸如 SetFetchMode("Bids", FetchMode.Lazy) 之类的方法显式控制这一行为,以在需要时禁用急加载?

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章