Hibernate利用Query接口进行HQL查询

时间:2021-08-02 07:45:55

一、Query的作用

Hibernate利用Query接口进行HQL查询


二、Query的使用方法

Hibernate利用Query接口进行HQL查询


三、参数设置

Hibernate利用Query接口进行HQL查询


四、实例应用

<span style="font-size:14px;">public static List getOrderDedailByOrderId(String orderId) {
Map<String, Object> paramMap = new HashMap<String, Object>();

StringBuffer sql = new StringBuffer("from OrderDetail as od where od.omorder.id=:id");
paramMap.put("id", orderId);

try {
OrderDetailBO bo = new OrderDetailBO();
return bo.list(sql.toString(), paramMap);
} catch (Exception ex) {

}
return null;

}</span>


<span style="font-size:14px;">/**
* 根据查询条件得到查询结果
*
* @param querySQL
* @param map
* 查询条件
* @return 查询结果
* @throws HibernateException
*/
public List list(String querySQL, Map<String, Object> map) throws Exception {
List list = null;
try {
session = sessionFactory.openSession();

String sql = rebuildOrgSql(querySQL, orgId, listAllOrgs);
Query query = session.createQuery(sql);
if (map != null) {
for (String key : map.keySet()) {
if (sql.indexOf(":" + key) != -1) {
query.setParameter(key, map.get(key));
System.out.println("param[" + key + "]==="
+ map.get(key));
}
}
}
list = query.list();
} catch (Exception e) {
PubLogs.dbLogError(new StringBuffer("获取查询列表失败!").append(
"PubHibernate.list(querySQL)").append(
"querySql=" + querySQL), e);
throw e;
} finally {
if (session != null && session.isOpen()) {
session.close();
}
}
if (list != null) {
covertNullToSpace(list);
}
return list;
}</span>




二、hibernate会话与数据库连接关系 以oracle数据库为例。

下面session专指hibernate的session,connection专指jdbc的连接。

主要讨论2个问题:“hibernate的session与连接的关系”、“程序中应该频繁打开、关闭session?,还是打开后数据库操作完成再关闭”。

一、hibernate的session与连接的关系;

    session与connection,是多对一关系,每个session都有一个与之对应的connection,一个connection不同时刻可以供多个session使用。
    有连接池的情况下(缺省就有一个自带的)session关闭后,connection不一定关闭,hibernate缺省使用自带的连接池(connection.pool_size值为最大连接数),因此,session.close()后,还可以查询到应用占用的连接:

     Hibernate利用Query接口进行HQL查询

   正常情况下,每个open的session都需要close掉,如果是单线程使用的话,那么查询oracle数据库的连接,则一直是一个connection,如果多线程使用的话,则可能是一个或多个(多线程的open如果错开时间,则一个,多线程如果几乎同时,则超过一个,小于或等于连接池数据),如果session只open,不close,则每次增加一个connection。

  通常每次页面请求是一个线程,模拟多线程,可以在jsp中用frameset,每个frame的src指向一个不同的session查询。也可以加断点,访问多个页面,后访问的先从断点执行,这样多线程交叉执行session操作,会发现在连接池连接较少时,会增加连接进到池中。

下面是一个jsp例子,每个frame里面都访问了数据库:

<frameset cols="200,200,*"  >
 <frame src="<%=GlobalNames.getWEB_APP()%>/sysman/roleAction.do?method=findAllRoles" name="rolelist" marginwidth="0" marginheight="0" >
 <frame src="<%=GlobalNames.getWEB_APP()%>/sysman/moduleList.do" name="modulelist" marginwidth="0" marginheight="0">       
 <frame src="<%=GlobalNames.getWEB_APP()%>/sysman/grantTree.do" name="granttree" marginwidth="0" marginheight="0">

</frameset>

 

下面是在open或close时,打印的信息:

 

Thread:Thread[http-8080-Processor21,5,main],session created:net.sf.hibernate.impl.SessionImpl@a75737
Thread:Thread[http-8080-Processor23,5,main],session created:net.sf.hibernate.impl.SessionImpl@ab835a
Thread:Thread[http-8080-Processor21,5,main]SESSION  closed:net.sf.hibernate.impl.SessionImpl@a75737
Thread:Thread[http-8080-Processor21,5,main],session created:net.sf.hibernate.impl.SessionImpl@3cbb4b
Thread:Thread[http-8080-Processor21,5,main],session created:net.sf.hibernate.impl.SessionImpl@3cbb4b
Thread:Thread[http-8080-Processor22,5,main],session created:net.sf.hibernate.impl.SessionImpl@1443800
Thread:Thread[http-8080-Processor21,5,main],session created:net.sf.hibernate.impl.SessionImpl@3cbb4b
Thread:Thread[http-8080-Processor21,5,main]SESSION  closed:net.sf.hibernate.impl.SessionImpl@3cbb4b
Thread:Thread[http-8080-Processor23,5,main]SESSION  closed:net.sf.hibernate.impl.SessionImpl@ab835a
Thread:Thread[http-8080-Processor22,5,main]SESSION  closed:net.sf.hibernate.impl.SessionImpl@1443800
Thread:Thread[http-8080-Processor21,5,main],session created:net.sf.hibernate.impl.SessionImpl@6279d
Thread:Thread[http-8080-Processor21,5,main]SESSION  closed:net.sf.hibernate.impl.SessionImpl@6279d

可见是交叉进行的,如果connection.pool_size设置为1,则执行完后,oracle的数据库连接查看为1个,如果connection.pool_size设置为10的话,oracle的数据库连接查看为2或3个。

二、程序中应该频繁打开、关闭session?,还是打开后数据库操作完成再关闭;

没有连接池的情况下,打开关闭连接很耗资源,因此不能经常打开关闭连接,有连接池的情况下,打开或关闭连接并不耗资源,上面2种方式各有利弊,

1、可以在程序必经之路,比如filter或者某个父类的方法中,统一关闭session,

      比如方法中 :session.find1; session.find2;session.find3;doSomeThing();

      find1、2、3中,若都不关闭session,则是使用同一个连接,直到完成后,到filter或其他设定的必经之路才统一关闭(通过线程关联ThreadLocal) ;

      对事务操作,及时提交回滚,但是session也统一到必经之路去关闭;

2、每次都open、close。

我的建议是采用方式2,即每次都open、close。

因为每次都打开、关闭并不太耗资源,且容易将数据库操作控制在数据库层,第1种方式,将数据库的关闭移动到其他层去处理了,不太好,且必经之路可能会有漏网之鱼,比如别人在plugIn时,使用数据库操作,忘记关闭,就泄露了。另外当大并发时,尽量用完连接就放回去供别的线程使用,否则如上面提到的如果doSomeThing();很耗时,导致连接等待,就影响其他线程比较严重了,虽然已经获得连接的线程能以最快速度处理完自己的事情。