在Spring整合 Hibernate中,對dao層訪問中提供了兩個操作。
(1)protected final Session getSession() throws DataAccessResourceFailureException,IllegalStateException;
spring api的解釋:
Obtain a Hibernate Session, either from the current transaction or a new one. The latter is only allowed if the "allowCreate" setting of this bean'sHibernateTemplate is "true".
Note that this is not meant to be invoked from HibernateTemplate code but rather just in plain Hibernate code. Either rely on a thread-bound Session or use it in combination with releaseSession(org.hibernate.Session).
In general, it is recommended to use HibernateTemplate, either with the provided convenience operations or with a custom HibernateCallback that provides you with a Session to work on.HibernateTemplate will care for all resource management and for proper exception conversion.
(2)public final HibernateTemplate getHibernateTemplate();
spring api的解釋:
Note: The returned HibernateTemplate is a shared instance.
通過http://blog.csdn.net/fenixshadow/archive/2007/09/26/1802277.aspx的分析:可知getHibernateTemplate由spring管理,始終使用一個session連接數據庫,而每次getSession()就會創建一個新的session連接數據庫,不被spring管理。
轉帖(一)http://blog.csdn.net/fenixshadow/archive/2007/09/26/1802277.aspx
都說Spring 和 Hibernate是絕配。今天有點小小心得,拿出來共享一下。
當我們費了九牛二虎之力終於把環境全配好之后,有一個問題擺在面前:
如何訪問數據庫?
通過繼承HibernateDaoSupport我們有兩個選擇:
getSession().createQuery("from Users");
getHibernateTemplate().find( "FROM Users);
用哪個呢?困惑啊。
網上找了找資料都是推薦用getHibernateTemplate,原因說的不是很清楚。
於是我做了如下測試:
分別循環調用getSession().createQuery("from Users");getHibernateTemplate().find( "FROM Users);
1000次
結果getSession()很快就包無法建立連接了。而getHibernateTemplate屁事沒有可以跑完。
通過后台觀察,使用getSession會在數據庫中留下很多SQL*Net message from client的連接,終止測試后連接自動釋放。
而getHibernateTemplate則從頭到尾都使用一個連接。
難道是getSession()不會自動釋放連接?
於是我又分別循環調用getSession().createQuery("from Users");getHibernateTemplate().find( "FROM Users);
5次
發現當前端程序一結束,getSession的5個連接立刻就釋放了。結合前面1000次時終止測試后連接自動釋放,可以說明getSession()是會自動釋放連接的。
結論:
1、getSession()和getHibernateTemplate都可以自動釋放連接(當然你的配置要正確),但是在一個線程內getSession會get很多個session(就是開很多個會話、連接),很可能導致數據庫連接超過上限。所以推薦使用getHibernateTemplate。
2、如果有些語句無法用getHibernateTemplate實現,可以使用getHibernateTemplate.execute使用HibernateCallback回調接口。
另:可以設定HibernateTemplate的AllowCreate為True,並在finally中關閉Session。也可以將true作為參數傳遞到super.getSession(..)方法中取得Session。這樣也可以,就是麻煩點。
參見:
http://springframework.org/docs/api/org/springframework/orm/hibernate3/HibernateTemplate.html
http://www.mxjava.com/blog/article.asp?id=246
請各位高手不吝賜教。
另:用myEclipse自動生成的HibernateDAO代碼中。4.1.1版本的myEclipse自動生成的findById方法使用的是getSession方法獲得連接,不過在6.0中已經修改為使用getHibernateTemplate方法。5.0的沒有測試。
轉帖(二)http://jeoff.blog.51cto.com/186264/133434
* 使用 hql 語句進行操作
* @param hql HSQL 查詢語句(使用回調函數訪問外部變量,必須是final的)
* @param offset 開始取數據的下標
* @param length 讀取數據記錄數
* @return List 結果集
*/
public List getListForPage ( final String hql , final int offset , final int length ) {
public Object doInHibernate ( Session session ) throws HibernateException, SQLException {
Query query = session.createQuery ( hql ) ;
query.setFirstResult ( offset ) ;
query.setMaxResults ( length ) ;
List list = query.list ( ) ;
return list ;
}
}) ;
return list ;
}
HibernateTemplate還提供一種更加靈活的方式來操作數據庫,通過這種方式可以完全使用Hibernate的操作方式。HibernateTemplate的靈活訪問方式是通過如下兩個方法完成:
qObject execute(HibernateCallback action)
qList execute(HibernateCallback action)
這兩個方法都需要一個HibernateCallback的實例,HibernateCallback實例可在任何有效的Hibernate數據訪問中使用。程序開發者通過HibernateCallback,可以完全使用Hibernate靈活的方式來訪問數據庫,解決Spring封裝Hibernate后靈活性不足的缺陷。HibernateCallback是一個接口,該接口只有一個方法doInHibernate(org.hibernate.Session session),該方法只有一個參數Session。
通常,程序中采用實現HibernateCallback的匿名內部類來獲取HibernateCallback的實例,方法doInHibernate的方法體就是Spring執行的持久化操作。具體代碼如下:
public class PersonDaoImpl implements PersonDao
{
// 私有實例變量保存SessionFactory
private SessionFactory sessionFactory;
// 依賴注入必須的setter方法
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
/**
*
* 通過人名查找所有匹配該名的Person實例
*
* @param name
* 匹配的人名
*
* @return 匹配該任命的全部Person集合
*
*/
public List findPersonsByName(final String name){
// 創建HibernateTemplate實例
HibernateTemplate hibernateTemplate =new HibernateTemplate(this.sessionFactory);
// 返回HibernateTemplate的execute的結果
return (List) hibernateTemplate.execute(
// 創建匿名內部類
new HibernateCallback(){
public Object doInHibernate(Session session) throws HibernateException{
// 使用條件查詢的方法返回
List result = session.createCriteria(Person.class)
.add(Restrictions.like("name", name+"%").list();
return result;
}
});
}
}
轉:HIBERNATE一二級緩存
Hibernate的一級緩存是由Session提供的,因此它只存在於Session的生命周期中,當程序調用save(),update(),saveOrUpdate()等方法,及調用查詢接口list,filter,iterate時,如Session緩存中不存在相應的對象,Hibernate會把該對象加入到一級緩存中,當Session關閉時,該Session所管理的一級緩存也會立即被清除。
- 注意:Hibernate的一級緩存是Session所內置的,不能被卸載,也不能進行任何配置
注意:Hibernate的一級緩存是Session所內置的,不能被卸載,也不能進行任何配置
一級緩存采用的是key-value的Map方式來實現的,在緩存實體對象時,對象的主關鍵字ID是Map的key,實體對象就是對應的value。所以說,一級緩存是以實體對象為單位進行存儲的,在訪問時使用的是關鍵字ID。雖然,Hibernate對一級緩存使用的是自動維護的功能,沒有提供任何配置功能,但是可以通過Session中提供的方法來對一級緩存的管理進行手工干預。
get與load的區別
使用get方法獲得持久化對象時,首先查找Session緩存(一級緩存)是否有該對象,如果有,則獲得該對象;如果沒有,就會訪問數據庫,如果數據庫中找不到數據,則返回null。
load方法也是獲得數據,但不同的地方是load方法已經假定數據庫中一定存在該數據,如果在數據庫中找不到該數據,則會拋出一個org.hibernate.ObjectNotFoundException異常。
load方法獲得對象的過程是:load方法首先在Session緩存中查找對象,如果找不到則查找SessionFactory緩存(二級緩存),如果再找不到則訪問數據庫。值得注意的是,load方法是假定數據庫中一定有該數據,所以使用代理來延遲加載對象,只有在程序中使用了該對象的屬性(非主鍵屬性)時,Hibernate才會進入load方法的獲得對象過程。所以說,如果數據庫中不存在該記錄,異常是在程序訪問該對象屬性時拋出的,而不是在創建這個對象時就拋出。