hibernate查询之执行查询

hibernate查询之执行查询 ----------

 

1.列出所有结果

  在hibernate中,list()方法执行查询并返回结果为java.util.List:

Query q = session.createQuery("from Item item"); List result = q.list(); 

Criteria接口也支持这个操作:

Criteria criteria = session.createCriteria(Item.class); List result = criteria.list(); 

 

在这两个案例中,是立即执行一个还是几个SELECT语句,这取决于你的抓取计划。有些结果只是单个实例的查询---例如,如果你只想要最高的出价。如果是这样,就可以利用resout.get(0)从结果清单中读取它。或者可以利用setMaxResult(1)限制返回的行数。然后,可以通过uniqueResult()方法执行查询,因为你知道只会返回一个对象:

Bid maxBid = session.createQuery("from Bid b order by b.amount desc").setMaxResults(1).uniqueResult(); Bid bid = (Bid)session.createCriteria(Bid.class).add(Restrictions.eq("id",id)).uniqueResult(); 

如果查询返回不止一个对象,就抛出异常。如果查询结果为空,就返回null。

 

 

2.循环访问结果

hibernate Query接口也提供iterate()方法来执行查询。它返回与list()一样的数据,但是依赖不同的策略来获取结果。调用iterate()执行查询时,hibernate在第一个SQL SELECT中只获取实体对象的主键(标识符)值,然后试图在持久化上下文高速缓存和二级高速缓存中查找对象的其它状态。

考虑如下代码:

Query categoryByName = session.createQuery("from Category c where c.name like :name"); categoryByName.setString("name",categoryNamePattern); List categories = categoryByName.list(); 

这个查询导致至少一个SQL SELECT的执行,CATEGORY表的所有列都包括在该SELECT子句中:

select CATEGORY_ID ,NAME,PARENT_ID from CATEGORY where NAME like ? 

 

如果你希望类别已经被高速缓存在持久化上下文或者二级高速缓存中,那就只需要标识符值(高速缓存的键)。这样就减少了从数据库中抓取的数据量。下列SQL效率更高一些:

select CATEGORY_ID from CATEGORY where NAME like ? 

可以给它使用iterate()方法:

Query categoryByName = session.createQuery("from category c where c.name like :name"); categoryByName.setString("name",categoryNamePattern); Iterator categories = categoryByName.iterate(); 

 

初始的查询只获取Category主键值,然后你循环访问结果,hibernate在当前的持久化上下文和二级高速缓存(如果启用的话)中查找每一个Category对象。如果高速缓存没有被访问到,Hibernate会给每次循环都执行一个额外的select,通过Category对象的主键,从数据库中完整地获取它。

在大多数情况下,这是一项很小的优化。把行读取减少到最少通常比把列读取减到最少更为重要。尽管如此,如果你的对象有很大的字符串字段,这种方法也可能有助于把网络中的数据名减到最少,因此把延迟也减到最小。应该清楚,只有当被迭代实体的二级高速缓存区域被启用时这种方法才真正有效。否则,它就会产生n+1次查询问题。

注:看来iterate()的使用环境是二级缓存启用了,同时该实体类被设置了二级缓存,这样才有效果。

 

 

 

3.利用数据库游标滚动

简单的JDBC提供一种特性,称作可滚动的结果集。这种方法使用一种保存在数据库管理系统中的游标。游标指向查询结果中一个特定的行,应用程序可以前后移游标。甚至可以通过游标跳到一个特定的行。

应该翻阅查询结果(而不是把它们全部加载到内存中)的其中一种情形是结果集太大而无法载入内存。通常可以尝试通过增加查询中的条件进一步限制结果。但有时候这是不可能的,或许因为你需要所有的数据,却又想要分几步获取。

这里我们使用ScrollableResults接口,如例:

ScrollableResults itemCursor = session.createQuery("from Item").scroll(); itemCursor.first(); itemCursor.last(); itemCursor.get(); itemCursor.next(); itemCursor.scroll(3); itemCursor.getRowNumber(); itemCursor.setRowNumber(5); itemCursor.previous(); itemCursor.scroll(-3); itemCursor.close(); //一定要关闭 

 

上面代码显示了ScrollableResults接口中最值得关注的方法。可以把游标设置到结果中的第一个(first())和最后一个(last())Item对象,或者使用获得游标当前正使用指向的Item(get())。可以通过setRowNumber()跳到一个位置,到达一个特定的Item,或者通过previous()和next()前后滚动。另一种方法是利用scroll(),通过偏移量前后滚动。执行Hibernate Criteria查询也可以通过滚动而不是list(),返回的ScrollableResults游标的工作原理相同。注意,在终止数据库事务之前、用完游标之后绝对必须关闭它。

下面是Criteria示例,展现了游标的打开:

ScrollableResults itemCursor = session.createCriteria(Item.class).scroll(ScrollMode.PORWARD_ONLY); ...//scroll only forward itemCursor.close(); 

Hibernate API的ScrollMode常量相当于简单JDBC中的常量。在这个示例中,该常量确保游标只能向前移动。这是必需的 ,以防万一,因为有些JDBC驱动程序并不支持向后滚动。其他可用的方法是ScrollMode.SCROLL_INSENSITIVE和ScrollMode.SCROLL_SENSITIVE。

 

 

 

 

 

 

你可能感兴趣的:(hibernate)