Hibernate的检索方式(一)
来源:互联网 发布:kmp算法程序 编辑:程序博客网 时间:2024/06/05 08:12
Hibernate提供了一下的几种检索对象的方式。
(1):导航对象图检索方式
根据已经加载的对象,导航到其他对象。如对于已经加载的Customer对象,调用它的getOrders().iterator()方法,就可以导航到所有关联的Order对象,假如在关联级别使用了延迟加载检索策略,那么首次执行此方法时,Hibernate会从数据库中加载关联的Order对象,否则就从Session缓存中取得Order对象。
(2):OID检索方式
按照对象的IOD来检索对象。Session的get()和load()方法提供了这种功能。
如果在应用程序中事先知道了OID,就可以使用这种检索对象的方式。
(3):HQL检索方式
使用面向对象的HQL查询语言。Hibernate还提供了Query接口,它是专门的HQL查询接口,能够执行复杂的HQL查询语句。
(4):QBC检索方式
使用QBC API来检索对象。
(5):本地SQL检索方式
一:HQL检索方式
HQL(Hibernate Query Language)是面向对象的查询语言。是使用最为广泛的一种方式。
具有以下的功能:
->:在查询语句中设定各种查询条件。
->:支持投影查询,即仅检索出对象的部分属性。
->支持分页查询。
->支持连接查询
->支持分组查询,允许使用having和group by关键字
->提供内置的聚集函数,如sum(),min()和max()。
->能够调用用户定义的SQL函数或者标准的SQL函数。
->支持子查询。
->支持动态的绑定参数
Query接口支持方法链的编程风格,它的setString()方法以及其他setXXX()方法都返回自身实例,而不是返回void 类型。
下面的例子用的数据表为:
(1):对查询结果进行排序
HQL采用order by关键字对象查询结果排序。
Query query = session.createQuery("from Customer as c order by c.name desc");
(2):分页查询
采用HQL检索方式:
Query query = session.createQuery(“from Customer c order by c.name asc”)
query.setFirstResult(0);
query.setMaxResults(10);
List result = query.list();
(3):检索单个对象(uniqueResult()方法)
(4):按照主键逐个处理插叙的结果(iterate()方法)
Query接口还提供了一个iterator()方法,它和list()方法一样。
只是二者使用的查询机制不一样。
(5):可滚动的结果集(略)
(6):在HQL查询语句中绑定参数
对于实际的应用,经常有这样的需求,用户在查询窗口中输入一些查询条件,要求返回满足条件的记录,如:用户提供了姓名和年龄信息,要求查询匹配的Customer对象。
应用程序可以定义一个findCustomers()方法来提供这一功能。
public static List findCustomers (String name) {Session session = HibernateSessionFactory.getSession();Query query = session.createQuery("from Customer as c where c.name =:_name");query.setString("_name", name);List list = query.list();HibernateSessionFactory.closeSession();return list;}
Tips:应该优先考虑使用按名字绑定方式。
(7):设置查询附属事项
在采用HQL检索方式或者QBC检索方式来检索数据库时,可以通过Query或者Criteria接口的一些方法来设定查询附属事项。
->setFlushMode()方法:设置清理缓存的模式。
->setCacheMode()方法:设置Session与第二级缓存的交互模式。
->setTimeout()方法:设置执行查询数据库操作的超时时间。
->setFetchSize()方法:为JDBC驱动程序设置批量抓取的数目。
->setLockMode()方法:设置锁定的模式。
->对于HQL检索方式,还可以通过Query接口的setReadOnly()方法来设置查询结果是否只允许读,而不允许修改。
设置清理缓存模式
当Session清理缓存时,会先进性脏检查,即比较Customer持久化对象的当前属性与它的快照,来判断Customer对象的属性是否发生了变化,如果发生了变化,就称这个对象是“脏对象”,Session的缓存有3中清理模式,
下表中列出3种清理模式各种执行清理缓存操作的时间点。
图:
FlushMode.AUTO是默认值,这也是优先考虑的清理模式,它会保证在整个事物中,Session缓存中的对象和数据库数据保持一致。如果事物仅仅包含查询数据库的操作,
而不会修改数据库中的数据,也可以选用FlushMode.COMMIT模式,这个可以避免在执行各种查询操作时先清理缓存,以便稍微提高应用程序的性能。
->设置批量抓取数目
以下程序代码通过setFetchSize()方法,把底层JDBC驱动程序进行批量抓取的数目设置为50:
List customers = session.createQuery(“from Customer”).setFetchSize(50).list();
以上Query接口的setFetchSize()方法和JDBC API中java.sql.Statement接口的setFetchSize()方法的作用是一样的,都是为底层JDBC驱动程序设置批量抓取数目。
那么为底层JDBC驱动程序设置批量抓取数目的意义。
下面的程序通过JDBC API查询CUSTOMERS表中的所有记录。
ResultSet rs = stmt.executeQuery(“select id,name from CUSTOMERS”);While (rs.next()) { String id = rs.getLong(1); ......}
假如CUSTOMERS表中有100000条记录,那么java.sql.Statement对象的executeQuery()方法返回的java.sql.ResultSet对象中是否立即存放了这100000条记录呢?假如ResultSet对象中存放了这么多记录,那将消耗多大内存空间啊。实际上,
ResultSet对象实际上并不会包含这么多的数据,只有当程序遍历结果集时,ResultSet对象才会到数据库中抓取相应的数据。ResultSet对象的抓取数据过程对程序完全透明。
那么,是否每当程序访问结果集中的一条记录时,ResultSet对象就要到数据库中抓取一条记录?按照这种方式抓取大量记录需要频繁的访问数据库,显然效率很低。为了提高减少访问数据库的次数,JDBC希望ResultSet接口的实现能支持批量抓取,每次从数据库中抓取多条记录,将它们存放在ResultSet对象的缓存中,让程序慢慢的使用。
在java.sql.Connection,java.sql.Statement和java.sql.ResultSet接口中都提供了setFetchSize(int size)方法。
在HQL中还可以调用SQL函数。
->:在HQL查询语句中调用函数(略)
->设定查询条件
和sql查询一样,HQL查询语句通过where子句来设定查询条件。
From Customer c where c.name=’Tom’
Tips:在where子句中给出的是对象的属性名,而不是字段名。
对于QBC查询,必须创建一个Criterion对象来设定查询条件。Restrictions类提供了创建Criterion实例的工厂方法:
Criteria criteria = session.createCriteria(Customer.class); Criterion nameEq = Restrictions.eq(“name”,”Tom”); criteria.add(nameEq);
HQL与QBC在设定查询条件中可用的各种运算符
图:->字符串模式匹配
和SQL查询一样,HQL用like关键字进行模糊查询,而QBC用Restrictions类的like()方法进行模糊查询。模糊查询能够比较字符串是否与指定的字符串模式匹配,
->集合运算
(1):检索不包含任何订单的Customer对象:
//HQL检索方式 List result = session.createQuery(“from Customer c where c.orders is empty”).list();
对于以上的HQL检索方式,Query的list()方法执行的SQL select 语句为:
Select ID,NAME,AGE from CUSTOMERS c where Not (exists(select o.ID from ORDERS o where c.ID=O.CUSTOMER_ID))
-----------------------------------------------------------------------------------------------------------------------------------
一:连接查询
HQL与QBC支持的各种连接类型
图:(1):默认情况下关联级别的运行时检索策略
在映射文件中可以设置关联级别的立即检索,延迟检索或迫切左外连接检索策略。
下面的程序代码没有显示指定与Customer关联的Order对象的检索策略:
//HQL检索方式 List result = session.createQuery(“from customer c where c.name like ‘T%’”); //QBC检索方式 List result = session.createCriterria(Customer.class); .add(Restrictions.like(“name”,”T”,MatchMode.START)).list();
此时将采用Customer.hbm.xml映射文件中对orders集合设置的检索策略,但有个例外,那就是HQL会忽略映射文件中设置的迫切左外连接检索策略。
(2):迫切左外连接
下面程序覆盖映射文件中指定的检索策略(),显示指定对于Customer关联的order对象采用迫切左外连接检索策略:(就算customer对象的orders集合设置了lazy为true,也会被忽略掉)
Query query = session.createQuery("from Customer c left join fetch c.orders o"); List result = query.list();
生成的SQL查询语句为:
Select c.id C_ID,c.name,c.age,o.ID O_ID,o.order_number ,o.customer_id from customers c left outer join Orders o on c.id = o.customer_id where (c.name like ‘T%’);
图:
在HQL查询语句中,left join fetch 关键字表示迫切左外连接检索策略。在
QBC查询中,FetchMode.JOIN表示迫切左外连接检索策略。使用迫切左外连接检索 策略时,Query或Criteria的list()方法返回的集合中存放Customer对象的引 用,每个Cusotmer对象的orders集合都被初始化,存放所有的关联的Order对象。
根据以上的查询结果,result 集合包含4个Customer类型的元素,其中前3个元素相同,都引用OID为1的Customer持久化对象,它的orders集合中包含3个Order对象,最后一个引用OID为5个Customer持久化对象。
图:由此可见,当使用迫切左外连接检索策略时,查询结果中可能包含重复元素,
可以通过一个HashSet来过滤重复元素:
List result = session.createCriteria(Customer.class); .setFetchMode(“orders”,FetchMode.JOIN); .add(Restrictions.like(“name”,”T”,MatchMode.START)) .list(); HashSet set = new HashSet(result); for (Iterator it = set.iterator();it.hasNext();) { Customer customer = (Customer)it.next(); ........ }
在HQL查询语句中,对于各种类型的连接,都可以为被连接的类指定别名,例如:
From Customer c left join fetch c.orders o Where c.name like ‘T%’ and o.orderNumber like ‘T%’;
以上的HQL查询语句为Customer赋予别名“c”,还为c.orders赋予别名“o”,
在查询语句中可以通过o.xxx的形式引用Order对象的属性。
Hibernate允许在一条查询语句中迫切左外连接多个多对一或一对一关联的类。
下面的图中显示了3个类的关联关系,其中类A和类B以及类A和类C都是多对一的关联关系。
图:以下二种检索方式是等价的,他们都能同时迫切左外连接类B和类C:
//HQL迫切左外连接检索方式
From A a left join fetch a.b b
Left join fetch a.c c
Where b is not null and c is not null;
//QBC迫切左外连接检索方式
List result=session.createCriteria(A.class);
.setFetchMode(“this.b”,FetchMode.JOIN);
.setFetchMode(“this.c”,FetchMode.JOIN);
.add(Restrictions.isNotNull(“this.b”));
.add(Restrictions.isNotNull(“this.c”));
假定有3个类,他们的关系下图,类A和类B以及类B和类C都是多对一关联关系。
图:
可以通过HQL来同时迫切左外连接B和C,但是QBC无法表达这种形式的迫切左外连接:
From A a left join fetch a.b b Left join fetch b.c c where b is not null and c is not null;
二:左外连接
以下HQL查询语句指定左外连接查询:
//HQL检索方式List result = session.createQuery("from Customer c left join c.orders where c.name like 'T%'").list();for (Iterator pairs = result.iterator();pairs.hasNext();){Object[]pair = (Object[])pairs.next();Customer customer = (Customer)pair[0];Order order = (Order)pair[1]; //如果orders集合使用延迟检索策略,以下代码会初始化Customer对象的orders集合。 Iterator orders = customer.getOrders().iterator();}
在HQL查询语句中,left join关键字表示左外连接查询。使用左外连接查询时,
将根据映射文件的配置来决定orders集合的检索策略,不过,即使在Customer.hbm.xml文件中对orders集合设置了延迟检索策略,在运行以上的list()方法时,Hibernate执行的SQL查询语句仍然与迫切左外连接生成的查询语句相同。
selectc.id C_ID c.name,c.age,o.id O_ID,o.order_number,o.customer_id from customers c left outer join orders o on c.id = o.customer_id where (c.name like ‘T%’);
Hibernate创建二个Customer持久化对象,他们的OID分别为1和5,还创建了3个Order对象,他们的OID为1,2和3。值得注意的时,Query的list()方法返回的集合中包含4个元素,每个元素对应的查询结果中的一条记录,每个元素都是对象数组类型,
图:从上图中可以看出,每个对象数都存放了一对Customer与Order对象。第一个对象数组引用OID 为1的Customer对象和OID为1的Order对象,第二个对象数组引用OID为1的Customer对象和OID为2的Order对象,第三个数组引用OID为1的Customer对象和OID为3的Order对象,第四个对象数组引用OID为5的Customer对象和null。
可见,前3个对象数组重复引用OID为1的Customers对象,此外,由于Custmer对象的orders集合采用延迟检索策略,因此他的orders集合没有被初始化。
当程序第一次调用OID为1的Customer对象的getOrders().iterator()方式时,会初始化Customer对象的orders集合,Hibernate执行的SQL查询语句为:
Select * from orders where customer_id = 1;
以上的查询返回3条ORDERS记录,由于和这3条记录对应的Order持久化对象已经存在,因此Hibernate不会在创建这些Order对象,仅让Customer对象的orders集合引用已经存在的Order对象:
图:如果希望Query的list()方法返回的集合中仅包含Customer对象,可以在HQL查询语句中使用select关键字:
List result = session.createQuery("select c from Customer c left join c.orders o where c.name like 'T%'").list();for (Iterator it = result.iterator();it.hasNext();){Customer customer = (Customer)it.next(); //如果orders集合使用延迟检索策略,以下代码会初始化 Customer对象的orders集合。 Iterator orders = customer.getOrders().iterator(); }
运行Query的list()方法时,Hibernate执行的SQL查询语句为:
Select c.id,c.name,c.age from customers c leftJoin orders o on c.id = o.customer_idWhere c.name like ‘T%’;
上面的查询语句的查询结果如下:
如图:
根据以上的查询结果,Hibernate创建二个Customer持久化对象,他们的OID分别为1和5.值得注意的时,Query的list()方法返回的集合中包含4个Customer类型的元素,
每个元素和查询结果中的一条记录对应:
图:
从图中看出,result集合中前3个元素都引用同一个Customer对象。此外,
由于Customer对象的orders集合采用延迟检索策略,因此orders集合没有被初始化。
当程序第一次调用OID为1的Customer对象的getOrders().iterator()方法时,会初始化Customer对象的orders集合,Hibernate执行的SQL查询语句为:
select * from orders where customer_id = 1;
以上查询语句返回3条ORDERS记录,由于和这3条记录对应的Order持久化对象还不存在,因此Hibernate会创建这些Order对象,并且让Customer对象的orders集合引用这3个Order对象:
如图:
三:内连接
在HQL中,inner join 关键字表示内连接如:
List result = session.createQuery(“from Customer c inner join c.orders o where c.name like ‘T%’”).list();for (Iterator pairs = result.iterator();pairs.hasNext();) { Object[]pair = (Object[])paris.next(); Customer customer = (Customer)pair[0]; Order order = (Order)pair[1]; //如果orders集合使用延迟检索策略,以下代码会初始化Customer对象的orders集合。 customer.getOrders().iterator();}
假如在Customer.hbm.xml文件中对orders集合设置了延迟检索策略,那么在运行Query的list()方法的时,Hibernate执行的SQL查询语句为:
Select c.id C_ID ,c.name ,c.age,o.id O_ID ,o.order_number ,O.customer_id from customers c inner join orders o on c.id =o.customer_id where (c.name like ‘T%’);
运行结果如下:
图:
根据以上查询结果,Hibernate会创建一个OID为1的customer持久化对象,还创建了3个Order对象,他们的OID分别为1,2,3。值得注意的是,Query的list()方法
返回的集合中包含3个元素,每个元素对应查询结果中的一条记录,每个元素都是对象数组类型,
如图:
从图可以看出,每个对象数组都存放了一对Customer与Order对象。第一个对象数组的应用OID为1的Customer对象和OID为1的Order对象,第二个对象数组引用OID为1的Customer对象和OID为2的Order对象,第三个对象数组引用OID为1的Customer对象和OID为3的Order对象。可见这3个对象数组重复引用OID为1的Customer对象。此外,由于Customer对象的orders采用延迟检索策略,因此orders集合没有被初始化。
当程序第一次调用OID为1的Customer对象的getOrders().iterator()方法时,会初始化Customer对象的orders集合,hibernate执行的SQL查询语句为:
Select * from orders where customer_id = 1;
以上的查询语句会返回3条orders记录,由于和这3条记录对应的order持久化对象已经存在,因此hibernate不会再创建这些order对象,仅让Customer对象的orders集合引用已经存在的order对象。
如图:
如果希望Query的list()方法返回的哦集合中仅包含Customer对象,可以在HQL查询语句中使用select关键字:
List result = session.creatQuery(“select c from customer c join C.orders o where c.name like ‘T%’”);For (Iterator it = result.iterator();it.hasNext();) { Customer customer = (Customer)it.next(); //如果orders集合使用延迟检索策略,以下代码会初始化Customer对象的orders集合 Iterator orders = customer.getOrders().iterator();}
运行Query的list()方法时,Hibernate执行的SQL查询语句为:
Select c.id ,c.name,c.age from customers cinner join orders o on c.id = o.customer_id;Where (c.name like ‘T%’);
图:
根据以上查询结果,Hibernate会创建一个OID为1的Customer持久化对象。值得注意的是,Query的list()方法返回的集合中包含3个Customer类型的元素:
如图:
当上图看出,result集合中3个元素都引用同一个Customer对象。此外,由于对
Customer对象的orders集合采用延迟检索策略,因此orders集合没有被初始化。
当程序第一次调用OID为1的Customer对象的getOrders().iterator()方法时,会初始化Customer对象的orders集合,Hibernate执行的sql语句为:
Select * from orders where customer_id = 1;
以上查询语句返回3条orders记录,由于和这3条记录对应的order持久化对象还不存在,因此Hibernate会创建这些Order对象,并且让Customer对象的orders对象orders集合引用这3个Order对象。
图:四:迫切内连接
以下程序覆盖映射文件中指定的检索策略,显示指定对与Cusomter关联的Order 对象采用迫切内连接检索策略:
//HQL检索方式List result = session.createQuery(“from Customer c inner join fetch c.orders o where c.name like ‘T%’”).list();for (Iterator it = result.iterator();it.hasNext();) { Customer customer = (Customer)it.next();}
以上代码生成的SQL查询语句为:
select c.id C_ID ,c.name ,c.age,o.id O_ID ,o.order_number,o.customer_id from customers c inner join orders o on c.id = o.customer_id where (c.name like ‘T%’);
图:
在HQL查询语句中,inner join fetch 关键字表示迫切内连接检索策略。使用迫切内连接检索策略时,Query的list()方法返回的集合中存放Customer对象的引用,每个
Customer对象的orders集合都被初始化,存放所有关联的Order对象。根据以上查询的结果,result集合包含3个Customer类型的元素,都引用OID为1的Customer持久化对象,它的orders集合中包含3个Order对象。
图:由此可见,当使用迫切连接检索策略时,查询结果中可能会包含重复元素,可以通过一个HashSet来过滤重复元素:
//HQL检索方式List result = session.createQuery(“from Customer c inner join fetch c.orders o where c.name like ‘T%’”).list();HashSet set = new HashSet(result);for (Iterator it = set.iterator();it.hasNext();) {Customer customer = (Customer)it.next();}
update:
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
//HQL检索方式
List result = session.createQuery("from Order o inner join fetcho.customer where o.customer.name like 'T%'").list();
/*
for (Iterator it = result.iterator();it.hasNext();) {
Customer customer = (Customer)it.next();
}*/
session.getTransaction().commit();
HibernateSessionFactory.closeSession();
Order order = (Order)result.get(0);
System.out.println(order.getCustomer().getName());
返回的结果为:
- Hibernate的检索方式(一)
- Hibernate的检索方式(一)
- Hibernate的检索方式(一)
- Hibernate的检索方式(一)
- Hibernate的检索方式(一)
- Hibernate的检索方式详解(一)
- Hibernate检索对象的方式(查询一)
- hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate 的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- Hibernate的检索方式
- display常用属性及inline元素之间的空白和padding的问题
- 基友记
- Java中说引用传递-这是不准确的
- 1815[Distance]
- mysql加密函数
- Hibernate的检索方式(一)
- test
- Oracle - SGA → Data_buffer_cache 之 Keep pool
- C++单例模式与线程安全
- 10491 - Cows and Cars (概率)
- 博客第一天,以后会多多交流的!
- oracle建立用户、表空间,给用户分配权限并分配表空间
- 复数的实现
- mysql的条件函数