hibernate学习笔记04----检索对象的方式
来源:互联网 发布:ubuntu怎么看硬盘大小 编辑:程序博客网 时间:2024/05/27 19:26
Hibernate查询数据方式
Hibernate是通过检索对象来查询数据的,下面我们了解一下,Hibernate提供的几种检索对象的方式:
l 对象导航检索方式:根据已经加载的对象导航到其他对象,主要针对关联集合对象的查询。(针对多表)
l OID检索方式:根据对象的OID来检索对象。(单表ById)
l HQL检索方式:使用面向对象的HQL(Hibernate Query Language)查询语言来检索对象,Hibernate底层会自动将HQL转换为SQL。
l Native SQL检索方式:本地(原生)SQL检索,使用本地数据库的SQL查询语句来检索对象。
l QBC检索方式:使用完全面向对象的QBC(Query By Criteria)的API来检索对象,该API底层封装了查询语句。
其中,前两种属于快捷检索方式,比较简单且常用,当这两种检索方式不能满足需要的时候,就需要使用后面几种检索方式,来自定义检索,如复杂检索条件等等。
1.1. 对象导航检索方式
什么是对象导航检索?
两个PO对象之间有关联,当应用程序已经拿到其中一个对象时,可以通过访问其关联到另外一个对象的属性,来隐式的获取到另外的关联对象数据。
如:Customer和Order对象的对象导航检索:
【示例】
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()
【三种方式的选择】
其中HQL和QBC是Hibernate推荐的检索方式,但性能上会有折扣,而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();}
【提示】
1.sql查询的默认结果是List<Object[]>(用数组包装了很多小customer),需要进行实体的绑定SQLQuery提供了addEntity方法。
2.SQL的语句生成方式:
Hql和sql的方式:语句是可控的,可以自定义的
Qbc:语句是完全由hibernate自己生成。
条件查询
HQL和SQL的查询时的条件值可以直接写死,也可以使用匿名参数(占位符?),还可以使用命名参数。
l 匿名参数(?):query.setParameter(索引,参数值)
l 命名参数(: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();}
【HQL和QBC支持的各种运算和对应关系】:
排序查询
【示例】
按照名字对客户信息进行排序。
//排序查询@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();}
【扩展oracle的sql语句的写法】
//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 HQL和SQL中可以通过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[]),如查询id和name,返回的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的一些特性,比如快照更新等。
如果字段确实非常多,为了提升性能,可以使用投影查询部分字段,(仅仅查询用)。
还有一种情况,必须使用投影!统计的时候!
- hibernate学习笔记04----检索对象的方式
- Hibernate检索对象的方式
- Hibernate检索对象的方式
- Hibernate检索对象的方式
- HIBERNATE检索对象方式
- 【Hibernate学习笔记】Hibernate的检索策略
- hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate 的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- hibernate的检索方式
- LeetCode Weekly Contest 34解题思路
- 类模板(二)
- 初探Meterpreter
- C++经典面试题
- 多重背包优化
- hibernate学习笔记04----检索对象的方式
- innodb buffer pool管理--LRU调整
- 银行家算法c++课程设计
- linux 下线程的创建
- 前端优化之-css与js阻塞问题
- Spring Bean xml显式装配之构造函数
- python 字典用法
- SecureCRT安装
- Python中if __name__ == "__main__": 的作用