4. Hibernate检索方式

Hibernate检索方式的分类web

Hibernate的检索方式主要有5种,分别为导航对象图检索方式、OID检索方式、HQL检索方式、QBC检索方式和SQL检索方式。下面对这5中检索方式的使用进行详解。spring

 

1. 对象图导航检索sql

对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。譬如要查找一个联系人对应的客户,就能够由联系人对象自动导航找到联系人所属的客户对象。固然,前提是必须在对象关系映射文件上配置了多对一的关系。其检索方式以下所示:数据库

  LinkMan linkMan = session.get(LinkMan.class, 1l);session

 Customer customer = linkMan.getCustomer();app

 

2. OID 检索方式dom

OID检索方式主要指用Session的get()和load()方法加载某条记录对应的对象。以下面两种加载客户对象的方式,就是OID检索方式,具体以下:函数

  Customer customer = session.get(Customer.class, 1l);学习

 Customer customer1 = session.load(Customer.class, 1l);测试

 

3. HQL检索

HQL(Hibernate Query Language)是面向对象的查询语言,它和SQL查询语言有些类似,但它使用的是类、对象和属性的概念,而没有表和字段的概念。在Hibernate提供的各类检索方式中,HQL是官方推荐的查询语言,也是使用最普遍的一种检索方式,它具备以下功能。

  • 在查询语句中设定各类查询条件;
  • 支持投影查询,即仅检索出对象的部分属性;
  • 支持分页查询;
  • 支持分组查询,容许使用group by 和 having关键字;
  • 提供内置汇集函数,如sum()、min()和max();
  • 可以调用用户定义的SQL函数;
  • 支持子查询,即嵌套查询;
  • 支持动态绑定参数;

Hibernate提供的Query接口是专门的HQL查询接口,它可以执行各类复杂的HQL查询语句,完整的HQL语句结构以下:

select...from...where...group by...having...order by ... asc/desc

能够HQL查询很是相似于表中SQL查询。一般状况下,当检索数据表中的全部记录时,查询语句中能够省略select关键字,示例以下所示:

String hql = "from Customer";

若是执行该查询语句,则会返回应用程序中的全部Customer对象。

须要注意的是:Customer是类名,而不是表名,类名须要区分大小写,而关键字from不区分大小写。

  3.1 基本检索

  

 1 @Test
 2     public void test1() {
 3         // HQL基本检索
 4         Transaction tx = session.beginTransaction();
 5         
 6         // 基本查询
 7         Query query = session.createQuery("from Customer");
 8         List<Customer> custList = query.list();
 9         for(Customer c : custList) {
10             System.out.println(c);
11         }    
12         tx.commit();
13     }

  3.2 条件检索

 1 @Test
 2     public void test2() {
 3         // 条件查询
 4         Transaction tx = session.beginTransaction();
 5         Query query = session.createQuery("from Customer order by cust_id desc");
 6         List<Customer> custList = query.list();
 7         for(Customer c : custList) {
 8             System.out.println(c);
 9         }
10         tx.commit();
11     }
 1     @Test
 2     public void test3() {
 3         // 按位置绑定参数
 4         Transaction tx = session.beginTransaction();
 5         Query query = session.createQuery("from Customer where cust_id=?");
 6 //        query.setInteger(0, 1);
 7         query.setParameter(0, 1l);
 8         List<Customer> list = query.list();
 9         for(Customer c: list) {
10             System.out.println(c);
11         }
12         tx.commit();
13     }
 1     @Test
 2     public void test4() {
 3         // 按名称绑定参数
 4         Transaction tx = session.beginTransaction();
 5         Query query = session.createQuery("from Customer where cust_id=:name");
 6 //        query.setInteger(0, 1);
 7         query.setParameter("name", 1l);
 8         List<Customer> list = query.list();
 9         for(Customer c: list) {
10             System.out.println(c);
11         }
12         tx.commit();
13     }
 1 @Test
 2     public void test5() {
 3         // 分页查询
 4         Transaction tx = session.beginTransaction();
 5         Query query = session.createQuery("from Customer");
 6         query.setFirstResult(0);
 7         query.setMaxResults(1);
 8         List<Customer> cusList = query.list();
 9         for(Customer c: cusList) {
10             System.out.println(c);
11         }
12         tx.commit();
13     }
1 @Test
2     public void test6() {
3         // 统计检索
4         Transaction tx = session.beginTransaction();
5         Query query = session.createQuery("select count(*) from Customer");
6         Long num = (Long) query.uniqueResult();
7         System.out.println(num);
8         tx.commit();
9     }
 1     @Test
 2     public void test7() {
 3         // 投影查询
 4         Transaction tx = session.beginTransaction();
 5         //投影查询一列
 6         Query query = session.createQuery("select cust_name from Customer");
 7         List<String> names = query.list();
 8         for(String s : names) {
 9             System.out.println(s);
10         }
11         //投影查询多列
12         Query query1 = session.createQuery("select cust_id, cust_name from Customer");
13         List<Object[]> cs = query1.list();
14         for(Object[] o : cs) {
15             System.out.println(Arrays.toString(o));
16         }
17         tx.commit();
18     }

 

4. QBC检索

QBC(Query By Criteria)是Hibernate提供的另外一种检索对象的方式,它主要有Criteria接口、Criterion接口和Expression类组成。Criteria接口是HibernateAPI中的一个查询接口,它须要由session进行建立。

Criterion是Criteria的查询条件,在Criteria中提供了add(Criterion criterion)方法添加查询条件。使用QBC检索对象的示例代码,以下所示:

 1     @Test
 2     public void test1() {
 3         Transaction tx = session.beginTransaction();
 4         criteria = session.createCriteria(Customer.class);
 5         // 设定查询条件
 6         criteria.add(Restrictions.eq("cust_id", 1l));
 7         // 获取查询结果
 8         List<Customer> list = criteria.list();
 9         System.out.println(list);
10         tx.commit();
11     }

QBC检索是使用Restrictions对象编写查询条件的,在Restrictions类中提供了大量的静态方法来建立查询条件。其经常使用的方法如表所示:

  方法名   说明
  Restrictions.eq     等于
  Restrictions.allEq   使用Map,使用key/value进行多个等于的比较
  Restrictions.gt   大于>
  Restrictions.ge    大于等于>=
  Restrictions.lt   小于
  Restrictions.le   小于等于<=
  Restrictions.between   对应SQL的between子句
  Restrictions.like   对应SQL的like子句
  Restrictions.in   对应SQL的IN子句
  Restrictions.and     and关系
  Restrictions.or   or关系
  Restrictions.sqlRestriction     SQL限定查询

4.1 基本检索

 1     @Test
 2     public void test2() {
 3         Transaction tx = session.beginTransaction();
 4         Criteria criteria = session.createCriteria(Customer.class);
 5 //        SimpleExpression restrictions = Restrictions.eq("cust_id", 1l);
 6 //        criteria.add(restrictions);
 7         List<Customer> list = criteria.list();
 8         for(Customer c : list) {
 9             System.out.println(c);
10         }
11         tx.commit();
12     }

 

4.2 条件检索

 1     @Test
 2     public void test3() {
 3         // 条件检索
 4         Transaction tx = session.beginTransaction();
 5         Criteria criteria = session.createCriteria(Customer.class);
 6 //        criteria.add(Restrictions.eq("cust_name", "test1"));
 7 //        criteria.add(Restrictions.like("cust_name", "%te%"));
 8         criteria.add(Restrictions.gt("cust_id", 1l));
 9         List<Customer> custList = criteria.list();
10         for(Customer c : custList) {
11             System.out.println(c);
12         }    
13         tx.commit();
14     }

4.3 分页检索

 1 @Test
 2     public void test4() {
 3         // 分页检索
 4         Transaction tx = session.beginTransaction();
 5         Criteria criteria = session.createCriteria(Customer.class);
 6         criteria.setFirstResult(0);
 7         criteria.setMaxResults(2);
 8         List<Customer> custList = criteria.list();
 9         for(Customer c : custList) {
10             System.out.println(c);
11         }    
12         tx.commit();
13     }

4.4 排序检索

 1 @Test
 2     public void test5() {
 3         // 排序检索
 4         Transaction tx = session.beginTransaction();
 5         Criteria criteria = session.createCriteria(Customer.class);
 6         criteria.addOrder(Order.desc("cust_id"));
 7         List<Customer> custList = criteria.list();
 8         for(Customer c : custList) {
 9             System.out.println(c);
10         }    
11         tx.commit();
12     }

4.5 统计检索

 1     @Test
 2     public void test6() {
 3         // 统计检索
 4         Transaction tx = session.beginTransaction();
 5         Criteria criteria = session.createCriteria(Customer.class);
 6         criteria.setProjection(Projections.rowCount());
 7         Long count = (Long) criteria.uniqueResult();
 8         System.out.println(count);
 9         tx.commit();
10     }

4.6 离线条件检索

DetachedCriteria翻译为离线条件查询,由于它是能够脱离Session来使用的一种条件查询对象,咱们都知道Criteria对象必须由Session对象来建立。那么也就是说必须先有Session才能够生成Criteria对象。而DetachedCriteria对象能够在其余层对条件进行封装。

这个对象也是比较有用的,尤为在SSH整合之后这个对象常常会使用。它的主要优势是作一些特别复杂的条件查询的时候,每每会在WEB层向业务层传递不少的参数,业务层又会将这些参数传递给DAO层。最后在DAO中拼接SQL完成查询。有了离线条件查询对象后,那么这些工做均可以不用关心了,咱们能够在WEB层将数据封装好,传递到业务层,再由业务层传递给DAO完成查询。

咱们能够先简单的测试一下离线条件查询对象,而后具体的使用咱们会在后期整合中使用,到那时会更加体会出它的优点。

 1     @Test
 2     public void test7() {
 3         // 离线条件查询:DetachedCriteria(SSH整合常用)
 4         // 能够脱离Session设置参数
 5         
 6         // 得到一个离线条件查询对象
 7         DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
 8         detachedCriteria.add(Restrictions.eq("cust_name", "test1"));
 9         Transaction tx = session.beginTransaction();
10         List<Customer> list = detachedCriteria.getExecutableCriteria(session).list();
11         for(Customer c : list) {
12             System.out.println(c);
13         }
14         tx.commit();
15     }

 

5. 本地SQL检索方式

采用HQL或QBC检索方式时,Hibernate生成标准的SQL查询语句,适用于全部的数据库平台,所以这两种检索方式都是跨平台的。但有的应用程序可能须要根据底层数据库的SQL方言,来生成一些特殊的查询语句。在这种状况下,能够利用Hibernate提供的SQL检索方式。使用SQL检索方式检索对象的示例代码,以下所示:

SQLQuery sqlQuery = session.createSQLQuery("select id,name,age,city from customer");

在这,SQL的检索方式咱们不作太多的介绍。以前不管咱们使用的是HQL或是QBC或是SQL其实都是单表的查询,而实际的开发中咱们每每须要多个表的联合查询才能够得到咱们想要的数据。

 

6. Hibernate的多表查询

在作多表查询以前,咱们须要先来回顾下使用SQL是如何完成多表的查询的。在学习SQL语句的时候进行多表联合查询通常都会采用链接查询,那么咱们就来回顾一下SQL中的多表的联合查询。

  6.1 链接查询

  • 交叉链接

交叉链接返回的结果是被链接的两个表中全部数据行的笛卡尔积,也就是返回第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数,例如department表中有四个部门,employee表中有四个员工,那么交叉链接的结果就是4*4=16条数据。

交叉链接的语法格式以下:

select * from 表1 CROSS JOIN 表2;

也能够写为以下格式:

SELECT * from 表1, 表2;

从上述描述状况能够看出,交叉链接的结果就是两个表中全部数据的组合。须要注意的是,在实际开发中这种业务需求不多见的,通常不会使用交叉链接,而是使用具体的条件对数据进行有目的的查询。

  • 内链接

内链接(INNER JOIN)又称简单链接或天然链接,是一种常见的链接查询。内链接使用比较运算符对两个表中的数据进行比较,并列出与链接条件匹配的数据行,组合成新的记录,也就是说在内链接查询中,只有知足条件的记录才能出如今查询结果中。内链接查询的语法格式以下所示:

select 查询字段 from 表1 [INNER] JOIN 表2 on 表1.关系字段=表2.关系字段

在上述语法格式中,INNER JOIN用于链接两个表,ON来指定链接条件,其中INNER能够省略。内链接其实还能够细分为以下两类:

    • 隐式内链接:顾名思义,隐式的就是咱们看不到inner join关键字,而是用where关键字替代。

    select * from 表1, 表2 where 表1.关系字段 = 表2.关系字段;

    • 显式内链接:显示的就是在语句中明显的调用了inner join的关键字。

    select * from 表1 inner join 表2 on 表1.关系字段 = 表2.关系字段;

    select * from 表1 join 表2 on 表1.关系字段 = 表2.关系字段;

  • 外链接

  前面讲解的内链接查询中,返回的结果只包含符合查询条件和链接条件的数据,然而有时还须要包含没有关联的数据,即返回查询结果中不只包含符合条件的数据,并且还包括左表(左链接或左外链接)、右表(右链接或右外链接)或两个表(全外链接)中的全部数据,此时就须要使用外链接查询,外链接分为左链接和右链接,外链接的语法格式以下:

select 所查字段 from 表1 left | rigth [outer] JOIN 表2 on 表1.关系字段 = 表2.关系字段 where 条件

外链接的语法格式和内链接相似,只不过使用的是LEFT JOIN、RIGHT JOIN关键字,其中关键字左边的表被称为左表,关键字右边的表被称为右表。

在使用左链接和右链接查询时,查询结果是不一致的,具体以下:

  6.2 LEFT JOIN(左链接): 返回包括左表中的全部记录和右表中符合链接条件的记录。

select * from 表1 left outer join 表2 on 表1.关系字段=表2.关系字段;

select * from A left join 表2 on 表1.关系字段 = 表2.关系字段;

  6.3 RIGHT JOIN(右链接):返回包括右表中的全部记录和左表中符合链接条件的记录。

select * from 表1 right outer join 表2 on 表1.关系字段 = 表2.关系字段;

select * from A right join 表2 on 表1.关系字段 = 表2.关系字段;

SQL语句的链接查询咱们会写了,那么Hibernate中的HQL如何进行链接查询呢?

 

6.2 HQL链接查询

Hibernate进行多表查询与SQL实际上是很类似的,可是HQL会在原来SQL分类的基础上又多出来一些操做。

HQL的多表链接查询的分类以下:

  • 交叉链接
  • 内链接
    • 显式内链接
    • 隐式内链接
    • 迫切内链接
  • 外链接
    • 左外链接
    • 迫切左外链接
    • 右外链接

其实,这些链接查询语法大体都是一致的,就是HQL查询的是对象而SQL查询的是表:

SQL链接查询:select * from cst_customer c inner join cst_linkman l on c.cust_id = l.lkm_cust_id;

HQL链接查询:from Customer c inner join c.linkmans

 

 

 

 

 

 

 

 

 

 

 

 

Hibernate懒加载策略

 在Hibernate中,<many-to-one.../>中的lazy默认为proxy。这样hibernate在数据库中查询数据时事不会把关联的对象查出来的,而是保存一个得到该值得方法:getXxxx()。当咱们须要使用这个值的时候,也就是使用getXxx()方法来调用的时候,Hibernate就会利用这个方法从数据库中获取相应的数据。可是很不幸,咱们的session早就关闭了。

这是由于Hibernate的懒加载策略,在Hibernate中是使用sessionFactory来管理session,咱们每进行一次数据库操做时都会新建一个session对象,当咱们操做完成后,hibernate就会在dao层当即关闭该session。这样作就能够严格控制session,避免出现低级错误。

 

下面给出三种解决办法,我的认为第二种比较好

   一、把lazy设成false。这个是最简单的办法,我的认为也是比较笨的方法。由于这是在用效率做为代价。

       二、使用OpenSessionInViewFilter。这种方法是将session交给servlet filter来管理,每当一个请求来以后就会开启一个session,只有当响应结束后才会关闭。以下:

1 <filter-name>hibernateFilter</filter-name>   
2      <filter-class>  org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class>   
3 </filter   
4 <filter-mapping>   
5      <filter-name>hibernateFilter</filter-name>   
6      <url-pattern>/*</url-pattern>   
7 </filter-mapping>  

上面的配置文件时在web.xml中配置的。

  三、将hibernate的抓起策略改成join。也就是是left join fetch或inner join fetch语法。就是在<many-to-one../>中配置lazy="false" fetch="join"便可。如:

1 <many-to-one name="worker" lazy="false" fetch="join" class="com.paixie.domain.Worker">  
2   
3          <column name="positionId"></column>  
4   
5     </many-to-one>  
相关文章
相关标签/搜索