天天看点

Hibernate的检索方式

hibernate支持五种方式检索

第一种导航对象图检索 : 在程序中已经获得持久态对象,通过对象关联关系去检索出相关对象数据

         例如 : Customer customer = session.get(Customer.class ,1 ); // 持久Customer

                            //由于customer关联了orders集合,hibernate就会自动生成SQL语句去检索 Order的数据

                            sysout(customer.getOrders.size());

第二种 OID检索方式: 根据id检索 session提供 get/load 方法

第三种 HQL检索方式 : 根据HQL语句检索 ,session.createQuery(HQL).list()

第四种 QBC(Query By Criteria)检索方式 :根据面向对象的Criteria对象检索。

                   session.createCriteria(xxx.class).list()

第五种本地SQL检索方式: 根据SQL语句检索,session.createSQLQuery(SQL).list()

         日常开发中第二种、第三种使用最多(Hibernate框架本身不适合特别复杂数据表关系进行查询,在真实开发中如果查询特别复杂会直接编写SQL语句!)

HQL 面向对象查询语句,语法和SQL类似, 可以实现SQL语句大部分功能 !

         HQL查询必须通过 Query接口,并且可以使用链式编程风格

         例:Query query = session.createQuery("from Customer where name =?");

                  query.setParameter(0, "张三");

                  List<Customer> customers =query.list();

         写为一句就叫做链式编程

         List<Customer>customers = session.createQuery("from Customer where name =?").setParameter(0, "张三").list();

1、使用HQL和QBC方式进行表中所有数据查询

         session.createQuery("fromCustomer").list();

         session.createCriteria(Customer.class).list();

2、使用SQL语句检索,并将查询结果封装到实体对象

         SQLQuerysqlQuery = session.createSQLQuery("select* from customer");

         封装到数组中:List<Object[]>list = sqlQuery.list();  ---- 默认的list 方法 返回 Object[] 的集合

         分装到对象中:SQLQuery 接口中提供方法 addEntity(xxx.class) 将查询结果封装到对象中(Query接口没有该方法)

         SQLQuerysqlQuery = session.createSQLQuery("select * from customer");

         sqlQuery.addEntity(Customer.class);// 将结果封装Customer对象

         List<Customer>customers = sqlQuery.list();这里就返回对象集合

         注:查询结果列,必须和绑定Entity中属性完全对应,如果 Entity中存在一个属性, 查询结果中没有对应列,就会抛出异常。

3、使用HQL和QBC方式进行带有条件的查询

         HQL 语句中可以通过“?“和“:参数名”两种方式设置参数

         HQL 绑定参数如果是基本数据类型, query提供 setParameter可以进行设置

         例:List<Customer> customers = session

              .createQuery("fromCustomer where name=? ")

              .setParameter(0, "张三").list();

    或者List<Customer>customers2 = session

              .createQuery("fromCustomer where name= :namevar")

              .setParameter("namevar", "张三").list();

         HQL绑定参数如果是一个对象类型,Query提供 setEntity绑定实体类对象(只会根据绑定对象OID 进行查询)

         例:查询 1号客户所有订单

         Customercustomer = new Customer();

         customer.setId(1);必须有id,别的属性不行

  List<Order>orders = session.createQuery("from Order where customer= ?").setEntity(0, customer).list();

问题: 如果查询张三客户的所有订单呢 ??

         List<Order>orders = session.createQuery("from Order where customer.name = ?").setParameter(0, "张三").list();

            查询1号客户订单

session.createQuery("from Order wherecustomer.id = ? ").setParameter(0, 1).list();

         QBC 方式执行条件查询    

根据条件查询的时候,只需要用add方法加上条件即可

问题: 查询姓名为张三的客户

         List<Customer>customers = session.createCriteria(Customer.class).add(Restrictions.eq("name","张三")).list();

问题 :查询 1号客户所有订单

         Customercustomer = new Customer();

         customer.setId(1);

         List<Order>orders = session.createCriteria(Order.class).add(Restrictions.eq("customer", customer)).list();

问题 :查询张三客户的所有订单

如果是根据关联对象除id之外其他属性查询,必须先将关联对象属性设置一个别名,才能进行 QBC查询,让criteria知道哪个是个对象,不是一个属性。createAlias方法就是用来指定别名的。

          List<Order> orders =session.createCriteria(Order.class) .createAlias("customer","c").add(Restrictions.eq("c.name", "张三")).list();

4、通过as设置别名

         通过HQL检索一个类的实例时,如果查询语句的其他地方需要引用它,应该为这个类指定一个别名

         fromCustomer as(可省) c where c.name=:custname

5、多态查询(了解)

         查询父类时,将所有PO子类对应数据表中数据查询出 

         例如: customer 有3条,order 有30条,查询Object,因为Object是 Customer和Order的父类, 将所有Customer和 Order 都查询,返回33条数据

// 查询所有客户
       List<Customer> customers = session.createQuery("from Customer").list();
       System.out.println(customers.size());//3条
       // 查询所有订单
       List<Order> orders = session.createQuery("from Order").list();
       System.out.println(orders.size());//30条
       // 查询所有Object
       // 如果查询类是PO类可以省略包名,不是PO类,必须要写完整包名
       List list = session.createQuery("from java.lang.Object").list();
       System.out.println(list.size());//33条
           

6、对查询结果排序

HQL :使用order by关键字进行排序

         List<Customer>customers = session.createQuery("from Customer orderby id desc").list();

QBC : hibernate提供 org.hibernate.criterion.Order完成排序,criteria.addOrder添加排序规则

         List<Customer>customers2 = session.createCriteria(Customer.class) .addOrder(org.hibernate.criterion.Order.desc("id")).list();

7、分页查询

         Query接口和Criteria 接口都提供 setFirstResult、setMaxResults 用于分页查询

setFirstResult:索引a,代表第a+1条数据

setMaxResults:查询多少条

         例:Query query = session.createQuery("from Order");

                  query.setFirstResult(10); //

                  query.setMaxResults(10); //

8、单一结果查询uniqueResult()方法使用

         Query接口和Criteria 接口都提供 uniqueResult() 用于处理单一结果查询

注:uniqueResult()如果返回1个或者0个结果没有异常(可以使用),如果返回结果>1会抛异常

作用: 根据id 查询、用户登录查询、使用分组函数(sum count avg max min ) 查询结果通常是唯一的

         例如: 查询数据库中共有多少个订单

                   long count = (Long)session.createQuery("select count(id) from Order").uniqueResult();

         注:分组函数一般返回的都是long型的数据。

9、命名查询语句(重点)

         将HQL语句写到代码中,不便于维护,或者可能出现重复的语句情况,这时就可以用到命名查询语句,将HQL、SQL语句写入配置文件,便于维护。

例:

在Customer.hbm.xml

                   <!--命名查询,为HQL语句 起一个名称 findCustomerByName -->

                   <query name="findCustomerByName">

                  为了在xml中不被解析,要加上CDATA语句。

                            <![CDATA[from Customer where name = ?]]>

                   </query>

在程序中通过名称,执行HQL语句           

                   QuerynamedQuery = session.getNamedQuery("findCustomerByName");

                   namedQuery.setParameter(0,"张三");参数还是要封装

                   List<Customer>customers = namedQuery.list();

10、使用QBC编程

         在使用QBC编程的时候,我们一定会向 Criteria 对象添加条件,条件对象在早期Hibernate版本中使用Expression 类获得,但现阶段企业开发已经主要用Restrictions,Expression已经过时。

Hibernate的检索方式

         例1: 查询北京的姓张的客户信息通过id降序

                   Criteriacriteria = session.createCriteria(Customer.class);

                   //模糊查询 提供 like 和 ilike ,ilike 忽略大小写

                   criteria.add(Restrictions.like("name","张%"));

                   //如果连续add ,默认连接符号 and

                   criteria.add(Restrictions.eq("city","北京"));

                   criteria.addOrder(org.hibernate.criterion.Order.desc("id"));

         例2: 查询来自北京的 或者 姓张的客户

                   criteria.add(Restrictions.or(Restrictions.eq("city", "北京"),Restrictions.like("name", "张%")));

11、多表关联查询

         SQL语句

         1)交叉连接(笛卡尔积)开发用的少,无意义。废数据多。

         2)内连接查询:左右表都存在对应的数据。

Hibernate的检索方式

         3)左外连接:保证左表数据完整,右表不一定。

Hibernate的检索方式

         4)右外连接:保证右表数据完整,左表不一定。

Hibernate的检索方式

         hibernate提供

         1)内连接、迫切内连接、隐式内连接

         2)左外连接、 迫切左外连接

         3)右外连接

         4)交叉连接

Hibernate的检索方式

主要区分: 内连接和迫切内连接,左外连接和迫切左外连接

         1、左外连接left join、迫切左外连接 left join fetch

         2、左外连接返回  List<Object[]> 每个数组两个元素,一个customer  一个 order

Hibernate的检索方式

         3、迫切左外连接 返回 List<Customer> 存在重复问题

Hibernate的检索方式

注:以上左外连接或者迫切左外连接都是包含表达式中第一个表中的数据(customer),对于迫切左外连接来说会出现很多重复数据,可以使用distinct排重。

List list = session

  .createQuery ("select distinct(c) fromCustomer c left join fetch c.orders").list();

12投影查询(重点)

         通过select 关键字只查询表中部分字段

HQL 方式投影(默认返回list<Object[]>)

         Listlist2 = session.createQuery("select name,cityfrom Customer").list();

QBC 方式投影(默认返回list<Object[]>)麻烦一般不写

         Listlist3 = session.createCriteria(Customer.class)

                                     .setProjection(Projections.projectionList().add(Property.forName("name"))

                                                                                                                                              .add(Property.forName("city"))).list();

只查询部分属性,将结果数据封装Customer对象。

         投影查询部分属性封装,可以 new list、 new map 、new 对象构造器

例:

在Customer 类提供构造器

         publicCustomer(String name, String city) {

                   super();

                   this.name= name;

                   this.city= city;

         }

         注:另外要加上无参数构造器

List list<Customer>= session.createQuery("selectnewCustomer(name,city) from Customer").list();

13、分组函数(聚集函数)

sum、count、avg、max、min

使用这些函数,返回值是一个单值 ,可以使用 Query.uniqueResult() 接收

14、离线查询(脱管查询)

DetachedCriteria:允许在没有Session 情况下,创建查询对象(添加查询条件)

         只要用于分层开发,一般在web层得到请求参数,然后传递给业务层再传递给持久层进行查询,但现在我们可以将请求参数封装成为一个查询对象,但是在web层没有session连接,这时候就能使用DetachedCriteria托管查询来封装查询对象,再将对象传递给持久层进行查询。      

public void demo15() {
	// 在没有Session情况下使用离线查询
	DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
	detachedCriteria.add(Restrictions.like("name", "张%"));

	Session session = HibernateUtil.openSession();
	Transaction transaction = session.beginTransaction();
	//在有session的时候进行封装
 List<Customer> customers =detachedCriteria.getExecutableCriteria(session).list();
	transaction.commit();
	session.close();
}

           

总结: hibernate框架执行简单查询可以用HQL或者QBC ,相对来说HQL 更加简单,但是在进行复杂条 件查询时,QBC不用拼接HQL语句,所以复杂查询优先使用QBC,但是在实际开发中,对于多表    复杂查询,hibernate 并没有很好的性能,一般都是通过手写SQL 来完成。