Hibernate中,left join、inner join以及left join fetch区别

本文详细解析了Hibernate中outer-join关键字的使用方法及其与懒加载的关系,并介绍了HQL语句中外连接的具体操作,包括join与fetch join的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、outer-join关键字(many-to-one的情况)

outer-join关键字有3个值,分别是true,false,auto,默认是auto。

true: 表示使用外连接抓取关联的内容,这里的意思是当使用load(OrderLineItem.class,"id")时,Hibernate只生成一条SQL语句将OrderLineItem与他的父亲Order全部初始化。

select * from OrderLineItem o left joinOrderpon o.OrderId=p.OrderId where o.OrderLineItem_Id=?

false:表示不使用外连接抓取关联的内容,当load(OrderLineItem.class,"id")时,Hibernate生成两条SQL语句,一条查询OrderLineItem表,另一条查询Order表。这样的好处是可以设置延迟加载,此处要将Order类设置为lazy=true。

select * from OrderLineItem owhere o.OrderLineItem_Id=?

select * from Order p where p.OrderId=?

auto:具体是ture还是false看hibernate.cfg.xml中的配置

注意:如果使用HQL查询OrderLineItem,如 from OrderLineItem o where o.id='id',总是不使用外部抓取,及outer-join失效。

2、outer-join(集合)

由于集合可以设置lazy="true",所以lazy与outer-join不能同时为true,当lazy="true"时,outer-join将一直是false,如果lazy="false",则outer-join用法与1同

3、HQL语句会将POJO配置文件中的关联一并查询,即使在HQL语句中没有明确join。

4、In HQL, the "fetch join" clause can be used for per-query specific outer join fetching. One important thing many people miss there, is that HQL queries will ignore the outer-join attribute you specified in your mapping. This makes it possible to configure the default loading behaviour of session.load() and session.get() and of objects loaded by navigating relationship. So if you specify

and then do

MyObject obj = session.createQuery("from MyObject").uniqueResult();

obj.getMySet().iterator().next();

you will still have an additional query and no outer-join. So you must explicily request the outer-join fetching:

MyObject obj = session.createQuery(

"from MyObject mo left join fetch mo.mySet").uniqueResult();

obj.getMySet().iterator().next();

Another important thing to know is that you can only fetch one collection reference in a query. That means you can just use one fetch join. You can however fetch "one" references in addition, as this sample from the Hibernate Docs demonstrates:

from eg.Cat as cat

inner join fetch cat.mate

left join fetch cat.kittens

We have once considered lifting this limitation, but then decided against it, because using more than one fetch-join would be a bad idea generally: The generated ResultSet becomes huge and is a major performance loss.

So alltogether the "fetch join" clause is an important instrument Hibernate users should learn how to leverage, as it allows tuning the fetch behaviour of a certain use case.

5、join fetch 与 join 的区别

如果HQL使用了连接,但是没有使用fetch关键字,则生成的SQL语句虽然有连接,但是并没有取连接表的数据,还是需要单独的sql取数据,也就是 select a,b,d...中没有连接表的字段

6、如果集合被声明为lazy=true,在HQL中如果显式的使用 join fetch 则延迟加载失效。

7、在one-to-many的one端显式设置fecth="join",则无论如何都采取预先抓取(生成一个SQl),延迟加载失效(生成两个SQL)

8、many-to-one的延迟加载是在配置文件的class标签设置lazy="true",one-to-many和many-to- many的延迟加载是在set标签中设置lazy="true"。而one-to-one不只要在calss标签设置lazy="true",而且要在 one-to-one标签中设置constrained="true".

<think>我们正在讨论JPA(特别是Hibernate作为实现)中的查询构建。用户的问题是关于在CriteriaQuery中使用root.join("requestNo")并手动添加等于条件是否会导致重复的JOIN操作。 首先,我们需要理解`root.join`的作用。在JPA Criteria API中,`root.join`用于指定一个关联(join)路径。当我们在一个关联属性上使用`join`方法时,Hibernate会生成相应的SQL JOIN。 用户提到“手动添加等于条件”,这可能指的是在`ON`子句中添加额外的条件,或者是在`WHERE`子句中添加条件?在Criteria API中,我们通常通过`Join.on`方法来添加`ON`子句的条件,或者通过`where`方法来添加`WHERE`子句的条件。 关键点:重复JOIN是否会发生? 1. **重复JOIN的情况**:如果我们多次对同一个关联路径进行JOIN,那么就会导致重复的JOIN。例如: ```java Join<Object, Object> join1 = root.join("requestNo"); Join<Object, Object> join2 = root.join("requestNo"); // 这会导致第二个JOIN ``` 2. **使用同一个Join对象添加多个条件**:如果我们只进行一次JOIN,然后使用这个Join对象添加多个条件(无论是在ON子句还是WHERE子句),那么不会导致重复JOIN。 用户的具体操作是:调用`root.join("requestNo")`一次,然后使用这个Join对象添加一个等于条件。例如: ```java Join<Object, Object> requestNoJoin = root.join("requestNo"); requestNoJoin.on(cb.equal(requestNoJoin.get("someColumn"), value)); ``` 或者是在WHERE子句中: ```java Join<Object, Object> requestNoJoin = root.join("requestNo"); Predicate equalPredicate = cb.equal(requestNoJoin.get("someColumn"), value); query.where(equalPredicate); ``` 在这种情况下,我们只进行了一次JOIN,所以不会产生重复JOIN。 但是,如果我们在同一个查询中多次对同一个关联路径调用`root.join`,那么每次调用都会创建一个新的JOIN,从而导致重复JOIN。 另外,Hibernate可能会自动处理关联,例如当我们通过路径表达式访问关联实体的属性时,Hibernate会自动生成JOIN(隐式JOIN)。但是,在Criteria API中,我们显式地使用`join`方法,所以控制权在开发者手中。 **结论**:如果只调用一次`root.join("requestNo")`,然后使用这个Join对象添加条件,那么不会导致重复JOIN。重复JOIN只有在多次对同一个关联路径调用`join`方法时才会发生。 **建议**:为了避免重复JOIN,我们应该确保对于同一个关联路径只调用一次`join`方法,并将返回的Join对象重用。 **相关问题**: 1. 在JPA Criteria API中,如何避免重复JOIN? 2. Hibernate在处理JOIN时有哪些优化策略? 3. 在JPA中,显式JOIN和隐式JOIN有什么区别?</think>### JPA/Hibernate 中 `root.join("requestNo")` 与手动添加等于条件是否导致冗余 JOIN 的分析 在 JPA Criteria API 中使用 `root.join("requestNo")` 并手动添加等于条件时,**通常不会产生冗余 JOIN**。以下是详细分析: #### 1. **JOIN 操作的本质** - 当调用 `root.join("requestNo")` 时,Hibernate 会在生成的 SQL 中创建 **一个显式 JOIN 语句**(如 `LEFT JOIN request_no`)[^4]。 - 手动添加等于条件(如 `cb.equal(join.get("id"), value)`)会生成对应的 `ON` 或 `WHERE` 子句条件,**不会额外增加 JOIN 数量**。 #### 2. **冗余 JOIN 的产生场景** 冗余 JOIN 通常发生在以下情况: - **多次调用 `join()` 同一路径**: ```java Join<?, ?> join1 = root.join("requestNo"); // 第一次 JOIN Join<?, ?> join2 = root.join("requestNo"); // 冗余 JOIN ``` - **隐式 JOIN 与显式 JOIN 混用**: ```java root.join("requestNo"); // 显式 JOIN cb.equal(root.get("requestNo").get("id"), value); // 隐式 JOIN(可能触发额外 JOIN) ``` #### 3. **正确用法(无冗余)** ```java CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<Entity> query = cb.createQuery(Entity.class); Root<Entity> root = query.from(Entity.class); // 显式 JOIN 并添加条件(推荐) Join<Entity, RequestNo> requestJoin = root.join("requestNo", JoinType.LEFT); query.where(cb.equal(requestJoin.get("id"), 123)); // 不会产生额外 JOIN ``` → 生成的 SQL 类似: ```sql SELECT ... FROM entity LEFT JOIN request_no ON entity.request_id = request_no.id WHERE request_no.id = 123 ``` #### 4. **Hibernate 的优化机制** - Hibernate 会尝试合并同一路径的重复 JOIN(通过 `PathSource` 跟踪已注册的 JOIN)[^4]。 - 但需注意:**跨不同查询段的 JOIN 可能无法合并**(如在 `SELECT` 和 `WHERE` 中分别调用 `join()`)。 #### 5. **验证方法** - 启用 Hibernate SQL 日志(`spring.jpa.show-sql=true`)检查生成的 SQL。 - 使用 `EXPLAIN` 分析查询计划,确认 JOIN 数量。 #### 结论 ✅ **正确使用**时(单次显式 JOIN + 条件),**不会产生冗余 JOIN**。 ❌ 冗余 JOIN 主要源于 **同一路径的重复调用** 或 **隐式/显式 JOIN 混用**。 --- ### 相关问题 1. 在 JPA Criteria API 中,如何避免生成冗余的 SQL JOIN 语句? 2. 隐式 JOIN(如 `root.get("a.b")`)和显式 JOIN(`root.join("a")`)的性能差异是什么? 3. Hibernate 的 `JOIN FETCH` 和普通 `JOIN` 在查询优化上有何区别? [^1]: JPA 与 Hibernate 关系解析 [^2]: JPA 规范定义 [^3]: JPA 持久化机制 [^4]: Hibernate 实现 JPA 的适配层设计
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值