hibernate学习笔记04----检索对象的方式

来源:互联网 发布:ubuntu怎么看硬盘大小 编辑:程序博客网 时间:2024/05/27 19:26

Hibernate查询数据方式

Hibernate是通过检索对象来查询数据的,下面我们了解一下,Hibernate提供的几种检索对象的方式:

对象导航检索方式:根据已经加载的对象导航到其他对象,主要针对关联集合对象的查询。(针对多表)

OID检索方式:根据对象的OID来检索对象。(单表ById

l HQL检索方式:使用面向对象的HQLHibernate Query Language)查询语言来检索对象,Hibernate底层会自动HQL转换为SQL

l Native SQL检索方式:本地(原生)SQL检索,使用本地数据库的SQL查询语句来检索对象。

l QBC检索方式:使用完全面向对象的QBCQuery By Criteria)的API来检索对象,该API底层封装了查询语句。

 

其中,前两种属于快捷检索方式,比较简单且常用,当这两种检索方式不能满足需要的时候,就需要使用后面几种检索方式,来自定义检索,如复杂检索条件等等。

 

1.1. 对象导航检索方式

什么是对象导航检索?

两个PO对象之间有关联,当应用程序已经拿到其中一个对象时,可以通过访问其关联到另外一个对象的属性,来隐式的获取到另外的关联对象数据。

如:CustomerOrder对象的对象导航检索:

【示例】

1).查询某客户信息,并且打印其下订单的数量;

2).查询某订单的信息,并打印其所属客户的信息。

//1).查询某客户信息,并且打印其下订单的数量;//2).查询某订单的信息,并打印其所属客户的信息。@Testpublic void testNavigate(){Session session = HibernateUtils.openSession();session.beginTransaction();//1).查询某客户信息,并且打印其下订单的数量;//Customer customer=(Customer)session.get(Customer.class, 1);////导航查询下属订单:(hibernate自动发出查询语句,不需要手动发出查询)//Set<Order> orders = customer.getOrders();////打印订单数量//System.out.println(orders.size());//2).查询某订单的信息,并打印其所属客户的信息。Order order =(Order)session.get(Order.class, 1);//通过导航方式获取所属的客户.不需要手动发出查询动作Customer customer1=(Customer)order.getCustomer();System.out.println(customer1);session.getTransaction().commit();//flushsession.close();}

【注意】

导航检索必须是持久态对象,否则不能导航

 

【导航检索的概念扩展】

导航检索就是在查询出某个的PO对象(持久态)后,再访问其关联的集合对象属性的时候,会自动发出SQL,来填充关联属性的所引用的对象。

如:查询客户后,再访问其订单属性的时候,Hibernate会自动发出查询订单的语句,并自动填充订单的值。



其他检索方式基本操作

OID检索方式:session.get(entity.class,id),session.load(entity.class,id)

HQL检索方式:session.createQuery(hql).list()uniqu

SQL检索方式(Native Query)session.createSQLQuery(sql).list(),

QBC检索方式:(Query by Criteria):session.createCriteria(Entity.class).list()


【三种方式的选择】

其中HQLQBCHibernate推荐的检索方式,但性能上会有折扣,而SQL的检索方式虽然效率很高,但不是面向对象的,开发上麻烦一些。


基础查询

【示例】

查询出所有客户信息。

@Test//基础查询:查询出所有客户的信息public void testBaseQuery(){Session session = HibernateUtils.openSession();session.beginTransaction();//hql:hql语句可以控制的,但具体的sql是自动生成。List<Customer> list1 = session.createQuery("from Customer").list();System.out.println(list1);//sql:自定义的sql语句,你写的啥语句,就发什么语句。//List<Object[]> list2=session.createSQLQuery("select * from t_customer").list();List<Customer> list2=session.createSQLQuery("select * from t_customer").addEntity(Customer.class).list();System.out.println(list2);//qbc:hibernate底层自动拼接语句,不会sql的人也能用,语句不可自定义控制。Criteria criteria = session.createCriteria(Customer.class);List<Customer> list3 = criteria.list();System.out.println(list3);session.getTransaction().commit();//flushsession.close();}

【提示】

1sql查询的默认结果是List<Object[]>(用数组包装了很多小customer),需要进行实体的绑定SQLQuery提供了addEntity方法。

2SQL的语句生成方式:

Hqlsql的方式:语句是可控的,可以自定义的

Qbc:语句是完全由hibernate自己生成。




 条件查询

HQLSQL的查询时的条件值可以直接写死,也可以使用匿名参数(占位符?),还可以使用命名参数。

匿名参数(?):query.setParameter(索引,参数值)

命名参数(:paramname):query.setParameter(命名参数,参数值)

【示例】

查询姓名是Rose的客户,只返回rose的一条记录。

@Test//条件查询//查询姓名是Rose的客户,只返回rose的一条记录。public void queryByCondition(){Session session = HibernateUtils.openSession();session.beginTransaction();//hql//写死值Customer customer11=(Customer)session.createQuery("from Customer where name='Rose'").uniqueResult();System.out.println(customer11);//匿名占位符?Customer customer12=(Customer)session.createQuery("from Customer where name=?").setParameter(0, "Rose").uniqueResult();System.out.println(customer12);//命名占位符   “:任意的名字"Customer customer13=(Customer)session.createQuery("from Customer where name=:cname1").setParameter("cname1", "Rose").uniqueResult();System.out.println(customer13);//扩展补充://上面的占位符的数据类型,其实是hibernate自动反射过去的//为了提升性能,可以自己指定类型,不使用自动反射Customer customer14=(Customer)session.createQuery("from Customer where name=?").setString(0, "Rose").uniqueResult();System.out.println(customer14);//sqlCustomer customer21=(Customer)session.createSQLQuery("select * from t_customer where name='Rose'").addEntity(Customer.class).uniqueResult();System.out.println(customer21);//匿名参数Customer customer22=(Customer)session.createSQLQuery("select * from t_customer where name=?").addEntity(Customer.class).setParameter(0, "Rose").uniqueResult();System.out.println(customer22);//命名参数Customer customer23=(Customer)session.createSQLQuery("select * from t_customer where name=:cname").addEntity(Customer.class).setString("cname", "Rose").uniqueResult();System.out.println(customer23);//qbc://没有占位符的说法,语句是不可控,自动生成,语句生成后,就是匿名占位符的Customer customer31 = (Customer)session.createCriteria(Customer.class).add(Restrictions.eq("name", "Rose"))//.add(criterion)//qbc的优势就是条件任意加,语句不需要考虑.uniqueResult();System.out.println(customer31);session.getTransaction().commit();session.close();}

HQLQBC支持的各种运算和对应关系】:




排序查询

【示例】

按照名字对客户信息进行排序。

//排序查询@Test//按照名字对客户信息进行排序。(倒序)public void testQueryByOrder(){Session session = HibernateUtils.openSession();session.beginTransaction();//hql:List<Customer> list1= session.createQuery("from Customer order by name desc").list();System.out.println(list1);//sql:List<Customer> list2= session.createSQLQuery("select * from t_customer order by name desc").addEntity(Customer.class).list();System.out.println(list2);//qbc:Criteria criteria = session.createCriteria(Customer.class);//排序:倒序criteria.addOrder(Order.desc("name"));List<Customer> list3 = criteria.list();System.out.println(list3);session.getTransaction().commit();//flushsession.close();}


分页查询

【示例】

将订单进行分页查询,每页10条记录,现在需要显示第二页的数据。

@Test//分页查询//将订单进行分页查询,每页10条记录,现在需要显示第二页的数据。public void testQueryByPage(){Session session = HibernateUtils.openSession();session.beginTransaction();//分页的逻辑分析和计算方式//相当于前台传递过来的分页数据int pageSize=10;//每页10条int page=2;//第二页//计算://起始索引int firstResult=(page-1)*pageSize;int maxResults=pageSize;//hql://setFirstResult(firstResult)设置起始索引//.setMaxResults(maxResults):设置最大查询的数量List<Order> list1 = session.createQuery("from Order").setFirstResult(firstResult).setMaxResults(maxResults)//最大条数.list();System.out.println(list1);//sql:limit 起始的索引,显示的最大条数List<Order> list21= session.createSQLQuery("select * from t_order limit "+firstResult+","+maxResults).addEntity(Order.class).list();System.out.println(list21);List<Order> list22= session.createSQLQuery("select * from t_order limit ?,?").addEntity(Order.class).setParameter(0, firstResult).setParameter(1, maxResults).list();System.out.println(list22);//qbc:Criteria criteria = session.createCriteria(Order.class);List<Order> list3 = criteria.setFirstResult(firstResult).setMaxResults(maxResults).list();System.out.println(list3);session.getTransaction().commit();//flushsession.close();}

【扩展oraclesql语句的写法】

//oracle:写的技巧:先在sql编辑器中写好,再复制进来改一改就行了。List<Order> list2 = session.createSQLQuery("SELECT * FROM (SELECT t.*,ROWNUM r FROM t_order t WHERE ROWNUM<="+(firstResult+maxResults)+") t2 WHERE t2.r>="+(firstResult+1)).addEntity(Order.class).list();System.out.println(list2);

投影查询

什么是投影查询

投影查询就是查询结果仅包含实体的部分属性,即只查询表中的部分指定字段的值,不全部查询。如:

select t.a,t.b,t.c from t;或者select count(*) from table; (是一种特殊的投影查询)


投影的实现:

l HQLSQL中可以通过SELECT关键字实现。

l QBC中,需要通过criteria.setProjection(投影列表)方法实现,投影列表通过add方法添加:Projections.projectionList().add(Property.forName("id"))


【示例】

查询用户的id和姓名。

@Test//投影查询//查询用户的id和姓名。public void testQueryByProjection(){Session session = HibernateUtils.openSession();session.beginTransaction();//hql://结果集根据结果,自动封装为Object[],不会自动封装回实体类//List<Object[]> list1 = session.createQuery("select id,name from Customer").list();//对象别名的//List<Object[]> list1 = session.createQuery("select c.id,c.name from Customer as c").list();//System.out.println(list1);//for (Object[] objects : list1) {//System.out.println("用户的编号:"+objects[0]+",用户的姓名:"+objects[1]);//}////使用别名查询所有数据//List<Customer> listall = session.createQuery("select c from Customer c").list();//System.out.println(listall);//sql://session.createSQLQuery("select id,name from t_customer ")//session.createSQLQuery("select c.id,c.name from t_customer as c")//hibernate会根据结果集的类型,自动封装(能往实体封就封,不能就封成object[]),无法addentityList<Object[]> list2 = session.createSQLQuery("select c.id,c.name from t_customer c")//.addEntity(Customer.class).list();System.out.println(list2);//qbc:Criteria criteria = session.createCriteria(Customer.class);//加上投影:结果集不会自动封装为实体,会根据结果的值自动封装为object数组//Projections.projectionList()投影列表,目标:在投影列表中加入投影(属性对象)//Property.forName("id"),引包Criterion包,使用了反射机制,将id字符串转换成id的属性,类似与Class.forName("驱动字符串")List<Object[]> list3 = criteria.setProjection(Projections.projectionList().add(Property.forName("id")).add(Property.forName("name"))).list();System.out.println(list3);session.getTransaction().commit();//flushsession.close();}

【注意】

经过投影查询的结果,默认都不会封装到实体类型中,而是根据实际查询的结果自动封装(object[]),如查询idname,返回的object[]list集合。

 

最大的坏处:一级缓存不放该对象。无法使用hibernate的一些特性,比如快照等等。

 

【应用提示】

实际hibernate开发中,一般较少使用投影查询(除了统计.一般我们都查询出所有字段,让其自动封装到实体类中就行了.


投影查询也可以封装到实体类中。

//查询用户的id和姓名。@Test//投影查询:只查询部分属性的值public void queryByProjection(){Session session = HibernateUtils.openSession();session.beginTransaction();//hql//结果集是根据返回的数据,自动封装为Object[],没有封装为实体对象//List<Object[]> list = session.createQuery("select id,name from Customer").list();//如果要封装为实体对象,需要提供一个投影属性的构造方法,不会再调用默认的构造器//尽管被封装为实体对象,但该对象,是个非受管对象。不是被session管理//List list = session.createQuery("select new Customer(id,name) from Customer").list();//System.out.println(list);//for (Object[] obj : list) {//System.out.println(obj[1]);//}//sql//结果集也是根据返回的数据的结果自动封装为Object[]List list2 = session.createSQLQuery("select id,name from t_customer")//设置结果集封装策略//类似于dbutil中的beanhandler,自动通过反射机制,自动将结果集封装到指定的类型中//.setResultTransformer(new AliasToBeanResultTransformer(Customer.class))//官方提供了一个工具类,简化代码编写.setResultTransformer(Transformers.aliasToBean(Customer.class)).list();//ResultTransformerSystem.out.println(list2);//qbcList list3 = session.createCriteria(Customer.class)//设置投影列表.setProjection(Projections.projectionList()//给属性起别名.add(Property.forName("id").as("id")).add(Property.forName("name").as("name")))//添加结果集的封装策略//发现了,该结果集封装策略,是根据字段的别名来自动封装//解决方案:增加别名.setResultTransformer(Transformers.aliasToBean(Customer.class)).list();//Projection//PropertySystem.out.println(list3);session.getTransaction().commit();session.close();}

小结:hibernate开发的情况下,一般,不使用投影,查询所有字段,因为查询出来的对象被hibernate管理,它是是一个受管对象。但如果使用投影,则将不是一个受管对象,无法使用到hibernate的一些特性,比如快照更新等。

如果字段确实非常多,为了提升性能,可以使用投影查询部分字段,(仅仅查询用)。

还有一种情况,必须使用投影!统计的时候!




原创粉丝点击