最近在用hibernate做项目,遇到了联合查询的问题,以及联合查询中的N+1问题。
针对无外键关联的联合查询,我做了HQL和SQL的实验,希望能帮助到大家。(我使用的版本是hibernate3.3.2)
1 几个常识:
(1)hql中的几种join查询,只有在外键关联、并且作了相应配置时才能使用。
(2)hql的默认查询策略,在进行联合查询时,会产生N+1问题,即先查询一次得到主键列表,然后根据主键查询N次数据库。
(3)hibernate有许多优化策略来避免N+1问题,但前提都是外键关联的情况下。
2 基本项目背景
不存在外键关联的几张表,具有各自的主键,需要进行联合查询。示例如下:
table fare<!--StartFragment-->
idint(11) NOT NULL PK,
desStnvarchar(255) NULL,
orgStnvarchar(255) NULL
table route
idint(11) NOT NULL PK,
desCodevarchar(255) NULL,
oriCodevarchar(255) NULL
fare表和route表是不存在外键关联的,我想利用hibernate进行联合查询,怎么办?
3 实验如下
我首先想到的是,利用HQL进行联合查询,因为可以避免写繁琐的getter和setter方法,如下:
@Test
public void testHQLSelect() {
session.beginTransaction();
List<FareRoute> list = session.createQuery("select new com.hibernate.FareRoute(f, r) from Fare f, Route r where f.orgStn=r.oriCode and f.desStn=r.desCode").list();
for (FareRoute fareRoute : list) {
System.out.println(fareRoute);
}
session.getTransaction().commit();
}
其中,Fare和Route分别是对应于fare表和route表的映射对象,FareRoute是自己定义的引用Fare和Route的类,用于前台显示。
这样子,是可以顺利的得到List<FareRoute>的,结果如下:
Hibernate: select fare0_.id as col_0_0_, route1_.routeId as col_1_0_ from Fare fare0_ cross join Route route1_ where fare0_.orgStn=route1_.oriCode and fare0_.desStn=route1_.desCode
Hibernate: select fare0_.id as id23_0_, fare0_.desStn as desStn23_0_, fare0_.orgStn as orgStn23_0_ from Fare fare0_ where fare0_.id=?
Hibernate: select route0_.routeId as routeId24_0_, route0_.desCode as desCode24_0_, route0_.oriCode as oriCode24_0_ from Route route0_ where route0_.routeId=?
Hibernate: select fare0_.id as id23_0_, fare0_.desStn as desStn23_0_, fare0_.orgStn as orgStn23_0_ from Fare fare0_ where fare0_.id=?
Hibernate: select route0_.routeId as routeId24_0_, route0_.desCode as desCode24_0_, route0_.oriCode as oriCode24_0_ from Route route0_ where route0_.routeId=?
Hibernate: select fare0_.id as id23_0_, fare0_.desStn as desStn23_0_, fare0_.orgStn as orgStn23_0_ from Fare fare0_ where fare0_.id=?
Hibernate: select route0_.routeId as routeId24_0_, route0_.desCode as desCode24_0_, route0_.oriCode as oriCode24_0_ from Route route0_ where route0_.routeId=?
Hibernate: select fare0_.id as id23_0_, fare0_.desStn as desStn23_0_, fare0_.orgStn as orgStn23_0_ from Fare fare0_ where fare0_.id=?
Hibernate: select route0_.routeId as routeId24_0_, route0_.desCode as desCode24_0_, route0_.oriCode as oriCode24_0_ from Route route0_ where route0_.routeId=?
Hibernate: select route0_.routeId as routeId24_0_, route0_.desCode as desCode24_0_, route0_.oriCode as oriCode24_0_ from Route route0_ where route0_.routeId=?
Hibernate: select route0_.routeId as routeId24_0_, route0_.desCode as desCode24_0_, route0_.oriCode as oriCode24_0_ from Route route0_ where route0_.routeId=?
Hibernate: select fare0_.id as id23_0_, fare0_.desStn as desStn23_0_, fare0_.orgStn as orgStn23_0_ from Fare fare0_ where fare0_.id=?
Hibernate: select route0_.routeId as routeId24_0_, route0_.desCode as desCode24_0_, route0_.oriCode as oriCode24_0_ from Route route0_ where route0_.routeId=?
Hibernate: select fare0_.id as id23_0_, fare0_.desStn as desStn23_0_, fare0_.orgStn as orgStn23_0_ from Fare fare0_ where fare0_.id=?
Hibernate: select fare0_.id as id23_0_, fare0_.desStn as desStn23_0_, fare0_.orgStn as orgStn23_0_ from Fare fare0_ where fare0_.id=?
Hibernate: select fare0_.id as id23_0_, fare0_.desStn as desStn23_0_, fare0_.orgStn as orgStn23_0_ from Fare fare0_ where fare0_.id=?
1-SHA-BJS-1-SHA-BJS
2-BJS-SHA-2-BJS-SHA
3-BJS-PEK-4-BJS-PEK
5-PEK-SHA-5-PEK-SHA
5-PEK-SHA-6-PEK-SHA
5-PEK-SHA-7-PEK-SHA
7-BBB-AAA-3-BBB-AAA
8-PEK-SHA-5-PEK-SHA
8-PEK-SHA-6-PEK-SHA
8-PEK-SHA-7-PEK-SHA
9-PEK-SHA-5-PEK-SHA
9-PEK-SHA-6-PEK-SHA
9-PEK-SHA-7-PEK-SHA
10-PEK-SHA-5-PEK-SHA
10-PEK-SHA-6-PEK-SHA
10-PEK-SHA-7-PEK-SHA
有过项目经验的同学,肯定知道这就是N+1问题,我尝试用left join、设置fetch、修改batch-size等方式进行优化,却由于fare表和route表不存在外键关联,均以失败告终。做了另外一个实验,如下:
@Test
public void testSQLSelect() {
session.beginTransaction();
List<Object[]> list = session.createSQLQuery("select * from fare f, route r where f.orgStn=r.oriCode and f.desStn=r.desCode").addEntity("f", Fare.class).addEntity("r", Route.class).list();
for (Object[] obj : list) {
FareRoute fr = new FareRoute((Fare)obj[0], (Route)obj[1]);
System.out.println(fr);
}
session.getTransaction().commit();
}
执行结果如下:
Hibernate: select * from fare f, route r where f.orgStn=r.oriCode and f.desStn=r.desCode
1-SHA-BJS-1-SHA-BJS
2-BJS-SHA-2-BJS-SHA
3-BJS-PEK-4-BJS-PEK
5-PEK-SHA-5-PEK-SHA
5-PEK-SHA-6-PEK-SHA
5-PEK-SHA-7-PEK-SHA
7-BBB-AAA-3-BBB-AAA
8-PEK-SHA-5-PEK-SHA
8-PEK-SHA-6-PEK-SHA
8-PEK-SHA-7-PEK-SHA
9-PEK-SHA-5-PEK-SHA
9-PEK-SHA-6-PEK-SHA
9-PEK-SHA-7-PEK-SHA
10-PEK-SHA-5-PEK-SHA
10-PEK-SHA-6-PEK-SHA
10-PEK-SHA-7-PEK-SHA
使用sql进行联合查询时,只查询了一次,避免了N+1的问题,通过addEntity指定了返回的类型,返回的时候对象数组的列表, 通过使用
for (Object[] obj : list) {
FareRoute fr = new FareRoute((Fare)obj[0], (Route)obj[1]);
}
得到了想要的FareRoute对象。
总结:使用SQL的方式,解决了没有外键关联的多表联合查询时的N+1问题,需要自己对得到的List<Object[]>进行一些处理,但是这个处理并不麻烦,我认为可以接受,这样算是在编码繁琐性和性能之间的一个折衷。
希望能帮助到大家,与大家共同进步。
相关推荐
hibernate关联查询 实例源码 java web 如果不明白hibernate关联查询不明白的可以看看,保证马上学会,注释,数据库都有,很简单易学的源码,谢谢下载!
在实际项目开发中,我们经常需要处理复杂的数据库查询,特别是涉及到多个表之间的关联查询。Hibernate作为一款流行的Java持久层框架,提供了一种非常便捷的方式来处理这些问题。本文将详细介绍如何利用Hibernate进行...
### Hibernate HQL 关联查询详解 #### 一、引言 在进行数据库操作时,关联查询是必不可少的一部分,尤其在处理复杂的数据结构时更是如此。Hibernate作为一种流行的Java持久层框架,提供了强大的对象关系映射(ORM...
根据提供的文件信息,我们可以深入探讨Hibernate中的连表查询方法及其应用。下面将详细介绍与标题、描述及部分代码相关的...需要注意的是,在编写连表查询时要充分考虑性能问题,避免因查询复杂度过高而导致性能瓶颈。
**hibernate关联查询详解** Hibernate,作为Java领域中的一款流行的ORM(对象关系映射)框架,极大地简化了数据库操作,使得开发者可以使用面向对象的方式来处理数据库事务。在实际项目中,我们经常需要处理对象...
hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,包含4个说明文档,分别详细解说了hibernate关联映射的...
关于hibernate的关联操作 分享下
Hibernate中的查询方法若HQL,详细讲解HQL与使用的具体例子
本练习主要涵盖了Hibernate中的关联关系,这是理解Hibernate核心概念的重要一环。 首先,我们需要理解什么是关联关系。在数据库设计中,关联通常指的是表与表之间的连接,例如一对一、一对多、多对一和多对多关系。...
本文将深入探讨如何使用Hibernate实现递归查询,以解决在数据层次结构中涉及父节点与子节点关系时的问题。递归查询通常用于处理树形结构的数据,例如组织结构、菜单系统或者文件目录等。 首先,我们需要了解递归的...
总结,"Hibernate 多表连接分页查询示范项目"是一个实用的示例,它展示了如何在实际应用中利用 Hibernate Criteria API 实现复杂查询和分页,对于学习和掌握 Hibernate 的高级特性和数据库操作技巧非常有帮助。...
本文将深入探讨在使用Hibernate进行MySQL查询时的一些关键知识点,以帮助开发者更好地理解和应用这些技术。 首先,我们需要理解Hibernate的核心概念。Hibernate通过提供一个中间层,将Java对象与数据库表进行映射,...
“Hibernate 级联查询”是指在使用Hibernate这个Java持久化框架时,如何处理对象之间的关联查询。Hibernate提供了级联操作来简化数据的保存、更新和删除等操作,使得开发者无需手动编写复杂的SQL语句,就能实现关联...
当我们需要进行更复杂的数据库查询时,Hibernate提供了丰富的高级查询功能,这正是“Hibernate的高级查询”这一主题的核心所在。 在Hibernate中,高级查询主要包括HQL(Hibernate Query Language)、Criteria API和...
在使用Hibernate进行数据查询时,有时会遇到需要使用子查询的情况。然而,正如你所描述的,Hibernate的HQL(Hibernate Query Language)并不直接支持在`FROM`子句后跟一个子查询,这与标准的SQL语法有所差异。在HQL...
本文将深入探讨“hibernate关联映射实例”中的关键知识点,包括一对多、多对多和继承映射,这些都是Hibernate中至关重要的概念。 1. **一对多关联映射**: 在现实世界中,一个实体可能会与多个其他实体相关联,...
**Hibernate函数** ...当ORM无法满足需求时,原生SQL查询则提供了一种灵活的方式,以直接操作数据库的能力来解决特定问题。理解和熟练运用这些特性,对于提升Java开发中的数据库操作效率至关重要。
最后,为了防止数据的安全性问题,比如防止SQL注入,使用Hibernate的查询API可以有效避免这类风险,因为它们都是预编译的,可以自动转义特殊字符。 总结,使用Hibernate在查询条件中创建List集合是Java开发中常见的...
### Hibernate联合主键详解 #### 1. 定义联合主键 在Hibernate中定义联合主键主要依赖于`<composite-id>`标签。如示例文件所示,`Users`类被设计为具有联合主键,该主键由`name`和`tel`两个字段组成。在`...
本文将深入探讨“Hibernate关联表问题”,基于给出的标题和描述,我们将重点讨论Hibernate中的多对多(Many-to-Many)关联映射。 在关系型数据库中,多对多关联是最复杂的一种关系,比如用户可以有多个角色,角色也...