Hibernate高级查询
来源:互联网 发布:负面情绪 知乎 编辑:程序博客网 时间:2024/04/30 15:12
一:动态查询
HQL与QBC能够完成许多相同的任务,相比之下,HQL能更加直观地表达复杂的查询语句。
而通过QBC来表达复杂的查询语句很麻烦。以下的两个代码完成相同的任务,但是HQL检索方式的程序代码更加简洁:
//HQL检索方式Query query=session.createQuery(“from Customer c” +”where (c.name like ‘T%’ and c.name like ‘%m’)” +”or (c.age not between 18 and 25)”);
//QBC检索方式Criteria criteria = session.createCriteria (Customer.class);criteria.add(Restrictions.or( Restrictions.add(Restrictions.like(“name”,”T%”)), Restrictions.like(“name”,”%m”)), Restrictions.not( Restrictions.between(“age”,new Integer(18), new Integer(25))))) ;
因此,如果在程序运行前就明确了查询语句的内容(也称为静态查询),应该优先考虑HQL查询方式。但是,如果只有在程序运行中才能明确查询语句的内容(也称为动态查询),QBC比HQL更加方便。
在实际应用中,经常有这样的查询需求:用户在客户界面的查询窗口输入查询条件,按下”查询按钮”后,业务层执行查询操作,返回匹配的查询结果。
以下的程序通过HQL来生成动态的查询语句,包含了大量的逻辑判断流程:
public static List findCustomers (String name,int age) throws HibernateException {StringBuffer hqlStr = new StringBuffer("from Customer c");if (name != null){hqlStr = hqlStr.append(" where lower(c.name) like :name");}if (age != 0 && name != null) {hqlStr.append(" and c.age = :age");}if (age != 0 && name == null) { hqlStr.append(" where c.age = :age");}Session session = HibernateSessionFactory.getSession();Query query = session.createQuery(hqlStr.toString());if (name != null) {query.setString("name", name);}if (age != 0) {query.setInteger("age", age);}return query.list();}
如果采用QBC检索方式,可以简化程序代码中的逻辑判断流程:
public List findCustomers(String name,int age)throws HibernateException { Criteria criteria = getSession().createCriteria(Customer.class); if (name != null) { criteria.add( Restrictions.ilike(“name”,name.toLowerCase(), MatchMode.ANYWHERE)); } if (age != 0) { criteria.add(Restrictions.eq(“age”,new Integer(age))); } return criteria.list();}
如果Customer对象的name属性为”T”,age的属性为21,Hibernate执行的sql语句为:
select id,name,age from customers where lower(name) like ‘%t%’ and age = 21;
二:集合过滤
对于应经加载的Customer持久化对象,假定它的orders集合由于使用延迟检索策略而没有被初始化,那么只要调用customer.getOrders().iterator()方法,Hibernate就会初始化orders集合,在初始化时从数据库中加载所有与Customer关联的Order持久化对象。这种方式存在两大不足:
-> 假定这个Customer对象与1000个Order对象关联,就会加载1000个Order对象。
在实际应用中,往往只需要访问orders集合中的部分Order对象,如访问价格大于100的Order对象,此时调用Customer.getOrders().iterator()方法会影响运行时性能,因此它会多余加载应用程序不需要访问的Order对象。
-> 不能对orders集合中的Order对象进行排序,如按照Order对象的价格或者订单的编号排序。
有两种解决上问题的变法,一种办法是通过HQL或QBC查询orders集合:
Customer customer = (Customer) session.load(Customer.class, new Long(1));List result = session.createQuery("from Order o where o.customer =:customer and o.price > 100 order by o.price").setEntity("customer",customer).list();Iterator it = result.iterator();while (it.hasNext()) {System.out.println(it.next());}
生成的SQL语句为,以及SQL查询语句为:
Hibernate: select order0_.id as id1_, order0_.order_number as order2_1_, order0_.price as price1_, order0_.customer_id as customer4_1_ from orders order0_ where order0_.customer_id=? and order0_.price>100 order by order0_.priceOrder [id=2, orderNumber=Tom_Order002, price=200.0]Order [id=3, orderNumber=Tom_Order003, price=300.0]
还有一种办法是使用集合过滤:
List result = session.createFilter(customer.getOrders(),”where this.price > 100 order by this.price”).list();Iterator it = result.iterator();while (it.hasNext()) { Order order = (Order)it.next(); .....}
生成的SQL语句为:
select order0_.id as id1_, order0_.order_number as order2_1_, order0_.price as price1_, order0_.customer_id as customer4_1_ from orders order0_ where order0_.customer_id = ? and order0_.price>100 order by order0_.price
Session的createFilter()方法用来过滤集合,它具有以下特点。
它返回Query类型的实例。
它的第一个参数指定一个持久化对象的集合,这个集合是否已被初始化并没有关系,‘
但它所属的对象必须处于持久化状态。对于以上程序代码,如果Customer对象处于游离状态或临时状态,Hibernate在运行时会抛出以下异常。
[java] org.hibernate.QueryException:The collection was unreferenced
它的第二个参数指定过滤条件,它由合法的HQL查询语句组成。
不管持久化对象的集合是否已被初始化,Query的list()方法都会执行SQL查询语句,到数据库中检索Order对象,对于以上程序代码,Hibernate执行的SQL查询语句为:
select id,order_number,price from orderswhere customer_id = 1 ans price > 100 order by price;
如果Customer对象的orders集合已经被初始化,为了保证Session的缓存中不会出现OID相同的Order对象,Query的list()方法不会创建Order对象,
仅返回已经存在的Order对象的引用,下图
如果Customer对象的orders集合没有被初始化,Query的list()方法会创建相应的Order对象,但是不会初始化Customer对象的orders集合:
如:
集合过滤除了用于集合排序或设置约束条件,还有其他用途,下面例子:
(1):为Customer对象的orders集合分页:
List result = session.createFilter(customer.getOrders(),”order by this.price asc”).setFirstResult(10).setMaxResults(50).list();
(2):检索Customer对象的orders集合中Order对象的订单编号:
List result = session.createFilter(Customer.getOrders(),”select this.orderNumber”).list();
(3):检索数据库中与Customer对象的orders集合中Order对象的价格相同的所有的Order对象:
List result = session.createFilter(customer.getOrders(), “select other from Order other where other.price = this.price”).list();
生成的SQL查询语句为:Hibernate: select order0_.id as id1_, order0_.order_number as order2_1_, order0_.price as price1_, order0_.customer_id as customer4_1_ from orders order0_, orders order1_ where order1_.customer_id = ? and order0_.price=order1_.price
(4):假定Order类与LineItem类一对多关联,而LineItem类与Item类多对一关联
。Item类表示商品,LineItem类表示订单中购买单项商品的信息。集合过滤可用于
检索Order对象的lineItems集合中Lineitem对象的Item:
List result = session.createFilter(order.getLineItems(),” select this.item ”).list();
二:子查询
HQL支持在where子句中嵌套入子查询语句。如:以下HQL查询语句返回具有1条以上订单的客户。
List customerLists = query.list(); from Customer c where 1 <(select count(o) from c.orders o);
子查询语句必须放在括号内。和以上HQL查询语句对应的SQL语句为: select * from customers c where 1 < (select count(o.ID) from orders o where c.id = o.customer_id)
相同的代码如下:(没有使用子查询)
Query query = session.createQuery("select c from Customer c left outer join c.orders o group by c.id having count(o) > 1");
关于子查询的用法,有以下几点说明。
(1):子查询可以分为相关子查询和无关子查询。
相关子查询是指子查询语句引用了外查询语句定义的别名,如本节开头的子查询语句引用了别名”c”,它是外层查询语句为Customer类定义的别名。无关子查询是指子查询与外层查询语句无关。
from Order o where o.price > (select avg(ol.price) from Order o1)
(2):HQL的子查询依赖于底层数据库对子查询的支持能力。并不是所有的数据库都支持子查询。例如,MySQL从4.1.x版本开始才支持子查询,而4.0.x或者更老的版本都不支持子查询。如果希望应用程序能够在不同的数据库平台之间的移植,应该避免使用HQL的子查询功能。无关子查询语句可以改写为单独的查询语句;相关子查询语句可以改写为连接查询和分组查询语句,例如,以下HQL查询语句也能查询具有一条以上订单的客户:
select c from Customer c join c.orders o group by c.id having count(o) > 1;
(3):如果子查询语句返回多条记录,可以用以下关键字来量化。
-> all:表示子查询语句返回的所有记录。
-> any:表示子查询语句返回的任意一条记录。
-> some:与 “any”等价
-> in:与”=any”等价
-> exists:表示子查询语句至少返回一条记录。
如:以下HQL查询语句返回所有订单的价格都小于100的客户:
from Customer c where 100 > all (select o.price from c.orders o);
生成的SQL语句为:select customer0_.id as id0_, customer0_.name as name0_, customer0_.age as age0_ from customers customer0_ where 100>all ( select orders1_.price from orders orders1_ where customer0_.id=orders1_.customer_id )
以下查询语句返回有一条订单的价格小于100的客户:
from Customer c where 100 > any (select o.price from c.orders o);
生成的SQL语句为:
select customer0_.id as id0_, customer0_.name as name0_, customer0_.age as age0_ from customers customer0_ where 100>any ( select orders1_.price from orders orders1_ where customer0_.id=orders1_.customer_id )
以下返回有一条订单的价格等于100的客户。
from Customer c where 100 = any (select o.price from c.orders o);或者: from Customer c where 100 = some(select o.price from c.orders o);或者:from Customer c where 100 in (select o.price from c.orders o);以下HQL查询语句返回至少有一条订单的客户:from Customer c where exists(from c.orders);
- Hibernate QBC高级查询
- Hibernate高级查询方法
- Hibernate QBC高级查询
- Hibernate高级查询实战
- Hibernate高级查询实战
- Hibernate高级查询方法
- Hibernate高级查询方法
- Hibernate QBC高级查询
- Hibernate高级查询实战
- Hibernate QBC高级查询 .
- Hibernate高级查询
- Hibernate高级查询
- Hibernate高级查询一
- Hibernate高级查询方法
- hibernate QBC高级查询
- Hibernate高级查询方法
- Hibernate高级查询
- Hibernate高级查询方法
- 面试题笔试题——数组排序交换次数
- linux系统信息查看命令
- Centos 6 安装Nvidia显卡驱动的详细方法
- 在线支付
- linux的mount(挂载)命令
- Hibernate高级查询
- 多线程同步-mutex
- 动态代理
- Irrlicht学习之创建GUI界面
- 字符串的内容一旦声明则不可改变 Why?
- STL中优先队列的使用方法
- 表单重复提交
- jsp连接mysql数据库
- (阶段三 dijkstra1.4)HDU 1596 find the safest road(最短路的变形题:求乘积,求最大值)