序言
之前对hibernate中的查询总是搞混淆,不明白里面具体有哪些东西。就是因为缺少总结。在看这篇文章之前,你应该知道的是数据库的一些查询操作,多表查询等,如果不明白,可以先去看一下 MySQL数据表查询操作详解 ,以至于看这篇文章不用那么吃力。
--WZY
一、hibernate中的5种检索方式
1.1、导航对象图检索方式
根据已经加载的对象导航到其他对象
例如:在前面的各种映射关系中,实体类包含对其他类对象的引用。
Dept d = (Dept) session.get(Dept.class,2);
d.getStaffSet().size(); //d对象关联Staff集合,hibernate会自动检索Staff数据。如何检索的,看下面图中发送的sql语句。
1.2、OID检索方式
按照对象的OID来检索对象
例如:session.get()/session.load()
这个大家度很熟悉了,就不用在这里过多的阐述了。
1.3、HQL检索方式
HQL:Hibernate Query Language ,是面向对象的查询语言,它和SQL查询语言有些相似,在Hibernate提供的各种检索方式中,HQL是使用的最广的一种检索方式,
注意:HQL操作的全是POJO类中的属性,而不是操作数据库表中的字段。
1.3.1、在查询语句中设定各种查询条件
1.3.2、支持投影查询,即仅检索出对象的部分属性
1.3.3、支持分页查询
1.3.4、支持连接查询
1.3.5、支持分组查询,允许使用HAVING 和 GROUP BY 关键字
1.3.6、提供内置聚集函数,如SUM(),MIN(),MAX()等
1.3.7、能够调用用户定义的SQL函数或标准的SQL函数
1.3.8、支持子查询
1.3.9、支持动态绑定参数
使用HQL检索步骤:
1>获得session
2>编写HQL
3>通过session.createQuery(HQL)创建Query对象
4>为Query对象设置条件参数(如果HQL中需要填充参数的话)
5>执行查询
list():返回一个集合列表,有可能集合中装的是数组,有可能是POJO对象。
uniqueResult():返回一个查询结果,在已知查询结果只有一个或者0个时,使用是没有问题的,如果返回结果有多个,那么就会报异常
实验
创建环境,使用Dept和Staff的双向一对多关系,其中具体的代码就不在列举出来了。重点不在这里。原始记录Staff中有9条记录,都指向了Dept中id为2的部门。
1.3.1、在查询语句中设定各种查询条件
1.3.1.1、查询全部记录,没有查询条件
View Code
结果
1.3.1.2、条件查询,查找出id=3的staff信息
View Code
1.3.2、支持投影查询,即仅检索出对象的部分属性
也就是不需要将表中所有的字段度查询出来,只查询出对象的部分属性,这就是投影查询
1.3.2.1、什么度不使用,直接查询,得到的结果就是将查到的属性全放到list集合中。这只使用于检索对象的一个属性,如果多个属性,就得需要用别的方式进行封装
View Code
1.3.2.2、使用new List()或者new Map()或new Staff()将返回的值给封装起来
使用new Staff()
View Code
使用new List()
View Code
使用new Map()
View Code
1.3.3、支持分页查询
使用setFirst()和setMaxResult()分别设置起始索引和拿去数据的总数。跟limit m,n 是一样的
View Code
1.3.4、支持连接查询
支持7种连接写法。
1.3.4.1、内连接 inner join 可以省略inner,直接join
View Code
1.3.4.2、迫切内连接 inner join fetch
内连接返回的list中是Object[],而迫切内连接返回的list中是POJO类对象
View Code
要想得到不重复的记录,那么就将hql改为"select distinct d from Dept d inner join fetch d.staffSet";
1.3.4.3、隐式内连接 不写任何关键字,完成表连接
其实就是通过where连接两张表。很简单。
View Code
1.3.4.4、左外连接,left outer join,可以省略outer,直接left join
View Code
1.3.4.5、迫切左外连接, left outer join fetch
一样的区别,就是list中存放的是POJO对象了
View Code
1.3.4.6、右外连接:right outer join
知道左外连接,右外连接也就会了。
View Code
1.3.4.7、交叉连接,会产生笛卡尔积。
什么是笛卡尔积?将两张表连接起来,比如一张表中有3条记录,另一张表中也有3条记录,那么连接之后,就会出现9条数据,其中就有一些重复的数据,拿实例说话,班级和学生,有三个学生A,B,C,有两个班级E,F,连接起来后,就会出现笛卡尔积,6条数据,其中会出现这样的数据,A,E 、A,F、B,E、B,F、C,E、C,F, A,B,C就重复出现了,即在E班级,又在F班级,这样就不合理。这就是所说的笛卡尔积。
由于dept中就一条记录,无法展示出笛卡尔积,所以手动增加一条dept的记录。然后在进行交叉连接。就会出现笛卡尔积,
View Code
注意:上面的连接中很多是使用一个引用就代表了相对应的表,比如" from Dept d inner join d.staffSet " d.staffSet就好像代表了Staff的这张表,实际上就是代表了Staff这张表,这样理解,from Dept 就从Dept表中找出了所有记录,就打比方,找到了Dept表中的2部门,在2部门中有多少staff呢,可以全部找出来,在我们所说的环境下,正好就staff就全部在该部门中,那么就找到了Staff表中的所有staff,也就是相当于是Staff这张表了,就算2部门没有包括所有的staff,那么还有其他部门,肯定包括了剩下的staff,也就是说,不管怎么样,度能把staff全部找到,所以d.staffSet就相当于Staff表了。以此类推,其他hql语句中的这里也是这样理解的。
1.3.5、支持分组查询,允许使用HAVING 和 GROUP BY 关键字
View Code
1.3.6、提供内置聚集函数,如SUM(),MIN(),MAX()等
这个例子中不好使用这几个函数。。。所以这里不演示了,很简单。hql和sql差不太多。
1.3.7、能够调用用户定义的SQL函数或标准的SQL函数
这个跟上面的一样,SQL中函数有很多。也就是说hql能够使用sql中的函数
1.3.8、支持子查询
View Code
1.3.9、条件查询,给hql中动态设置参数的两种方式
方式一:from Staff where id = ? 使用?代替所需要填入的值,在下面设置值时则从0开始算起,第一个?是处于0的位置,如果有两个?号,则使用0,1索引号来插入值。
View Code
方式二:from Staff where id = :id 使用":id"这个名字来表示插入值的名称,在下面则不用索引号来确定插入值的位置,直接是使用这个别称
View Code
注意,在位置上不仅仅可以插入值,还可以插入一个对象。例如
View Code
这两种方式度可以,不过在参数比较多的情况下,建议使用别名,那样更加清楚,不易出错,在少量参数时可以使用索引。
1.4、QBC检索方式
QBC:Query By Criteria,是一种更加面向对象的查询语言,提供的一系列QBC API来检索对象。
HQL所能做的事情,使用QBC也大多能做用,这个通过实例来看看QBC是如何使用的。
步骤:
1>获得session
2>session.createCriteria(Obejct.class); 创建criteria对象
3>使用criteria的API方法进行条件的增加。add(Restrictions.eq(属性名,值))
4>执行查询
list():返回一个集合列表,有可能集合中装的是数组,有可能是POJO对象。
uniqueResult():返回一个查询结果,在已知查询结果只有一个或者0个时,使用是没有问题的,如果返回结果有多个,那么就会报异常
例子一:使用QBC来对Staff进行查询
View Code
例子二:使用QBC来对Staff进行条件查询
View Code
例子三:QBC也能进行连接查询
View Code
给一张表来看看qbc增加的条件查询语句。
重点有一个离线Criteria对象的用法。
1、在web层封装查询条件到离线Criteria对象中,将其DetachedCriteria对象绑定到Thread上。
2、到dao层,就能通过Thread拿到该离线Criteria对象,然后创建session。将session给DetachedCriteria,就能够执行查询
代码:
WEB层
DetachedCriteria detachedCriteria =DetachedCriteria.forClass(Customer.class);
detachedCriteria.add(Restrictions.eq("name", "kitty"));
DAO层
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
// 将离线查询对象 关联到Session
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
Customer customer = (Customer) criteria.uniqueResult();
1.5、本地SQL检索方式
使用标准的SQL语句来编写。
步骤:
1>获得session
2>编写sql语句
3>session.createSQLQuery(sql);获取SQLQuey对象
4>给sql语句设置参数。
5>执行查询
list():返回一个集合列表,集合中装的是Object[]。
返回实体类对象集合,如果与实体类进行了绑定,也就是使用了addEntity(xxx.class)。
例子一:查询Staff的所有记录
View Code
例子二:查询Staff的所有记录,并且绑定实体。 addEntity。
View Code
二、总结
以上就是我们说的5种检索,其中说的重点就是hql的用法,上面的例子全部写完了差不多就对hql有一定的了解。记住hql是对pojo类进行操作,而不是对数据库中的表。在使用连接查询时,可以使用QBC,因为更简单,只需要用createAlias()就能使用任何的连接。一般在开发中sql语句都会提取出来放到hbm中,例如
在hbm映射文件 (也可以用注解配置)
<!-- 这里可以定义命名查询 -->
<!-- 定义 HQL 语句 <query name=""></query> -->
<!-- 定义 SQL 语句 <sql-query name=""></sql-query> -->
<query name="findCustomerByName">
<![CDATA[from Customer where name = ?]]>
</query>
* 为hql语句 起了一个名字
程序代码:
//相当于把sql语句分离开来了。方便维护
Query query = session.getNamedQuery("findCustomerByName");
query.setParameter(0, "tom");
Customer customer = (Customer) query.uniqueResult();