引文出處http://shenzhenchufa.blog.51cto.com/730213/156184
在網上看到一篇 關於getSession().method()和getHibernateTemplate().method()比較的文章,自己感覺有些
有些偏差(當然這隻限我個人的看法對錯與否還請各位批評指正),我會在原文各處提出我的看法。引文如下:
在ssh或ssh2中,對資料庫進行操作的DAO,都可以通過繼承HibernateDaoSupport來實現對資料庫的操作.
繼承後的實現方式有兩種:
super.getSession().A();
getHibernateTemplate().B();
用哪個好呢?
網上都是推薦用getHibernateTemplate,原因是:
getSession()和getHibernateTemplate都可以自動釋放串連(當然你的配置要正確),但是在一個線程內,
若同一時間進行很多次的操作(如:1000次查詢),getSession 會get很多個session(就是開很多個會話、串連),
很可能導致資料庫連接超過上限。所以推薦使用getHibernateTemplate。
<--- 以下是我的看法
若你的配置是 spring2 + hibernate2。
無論是getSession()還是getHibernateTemplate()調用追溯最終會發現,它們都調用了
SessionFactoryUtils的doGetSession(...),首先從TransactionSynchronizationManager管理的本地
線程變數中尋找是否存在一個SessionHolder,SessionHolder中是否包含Session,如當前線程沒有綁定一個
Session變數,則建立一個Session變數,如下:
/**
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using {@link HibernateTransactionManager}. Will create a new
* Session otherwise, if "allowCreate" is <code>true</code>.
* <p>Same as {@link #getSession}, but throwing the original HibernateException.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param entityInterceptor Hibernate entity interceptor, or <code>null</code> if none
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (may be <code>null</code>)
* @param allowCreate whether a non-transactional Session should be created
* when no transactional Session can be found for the current thread
* @return the Hibernate Session
* @throws HibernateException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and
* "allowCreate" is <code>false</code>
*/
private static Session doGetSession(
SessionFactory sessionFactory, Interceptor entityInterceptor,
SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)
throws HibernateException, IllegalStateException {
Assert.notNull(sessionFactory, "No SessionFactory specified");
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if (sessionHolder != null && !sessionHolder.isEmpty()) {
// pre-bound Hibernate Session
Session session = null;
if (TransactionSynchronizationManager.isSynchronizationActive() &&
sessionHolder.doesNotHoldNonDefaultSession()) {
// Spring transaction management is active ->
// register pre-bound Session with it for transactional flushing.
session = sessionHolder.getValidatedSession();
if (session != null && !sessionHolder.isSynchronizedWithTransaction()) {
logger.debug("Registering Spring transaction synchronization for existing Hibernate Session");
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.NEVER, which needs to allow flushing within the transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.lessThan(FlushMode.COMMIT) &&
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
}
else {
// No Spring transaction management active -> try JTA transaction synchronization.
session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator);
}
if (session != null) {
return session;
}
}
logger.debug("Opening Hibernate Session");
Session session = (entityInterceptor != null ?
sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());
// Use same Session for further Hibernate actions within the transaction.
// Thread object will get removed by synchronization at transaction completion.
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// We're within a Spring-managed transaction, possibly from JtaTransactionManager.
logger.debug("Registering Spring transaction synchronization for new Hibernate Session");
SessionHolder holderToUse = sessionHolder;
if (holderToUse == null) {
holderToUse = new SessionHolder(session);
}
else {
holderToUse.addSession(session);
}
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.NEVER);
}
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != sessionHolder) {
TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
}
}
else {
// No Spring transaction management active -> try JTA transaction synchronization.
registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder);
}
// Check whether we are allowed to return the Session.
if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {
closeSession(session);
throw new IllegalStateException("No Hibernate Session bound to thread, " +
"and configuration does not allow creation of non-transactional one here");
}
return session;
}
因此,若在一個線程內,且沒有被納入事務內,getSession()和getHibernateTemplate()是一樣的,每次調用它們都會
建立一個Session和建立一個connection。
若已被納入事物內,它們無論是單獨使用還是混合使用都會是使用的同一個session和connection.
我認為上面說法(getSession 會get很多個session ,就是開很多個會話、串連很可能導致資料庫連接超過上限。
所以推薦使用getHibernateTemplate。)不對。
--->
(1)------------------------------------------
getSession的各種用法:
查詢:
super.getSession().find()
super.getSession().createQuery()
儲存:
super.getSession().save()
super.getSession().update()
super.getSession().delete()
query的用法:
select,update,delete,分頁都可通過Query來執行:
-1->用query的好處,可以像PreparedStatement一樣,可以設定參數.
-2->且不用Iterate,因為只是判斷有沒值,所以,用list.size()判斷,若有值,也只有一個,即用list(0)來擷取即可
-3->同時,query,不但可用於查詢,還可以用於更新:
String hql = "UPDATE User SET userpwd=? WHERE userid=?";
Query q = super.getSession().createQuery(hql);
q.setString(0, userpwd);
q.setString(1, userid);
q.executeUpdate();
-4->也可delete:
String hql = "DELETE FROM Item WHERE itemid=?";
Query q = super.getSession().createQuery(hql);
q.setInteger(0, itemid);
q.executeUpdate();
-5->用query進行分頁:
List all = null;
String hql = "FROM Question AS q WHERE q.itemid=?";
Query q = super.getSession().createQuery(hql);
q.setInteger(0, itemid);
q.setFirstResult((currentPage - 1) * lineSize);
q.setMaxResults(lineSize);
all = q.list();
如:
Query query = session.createQuery("from User");
query.setFirstResult(0);//從第一條記錄開始
query.setMaxResults(4);//取出四條記錄
List userList = query.list();
(2)------------------------------------------
hibernateTemplate:
HibernateTemplate的常用方法簡介:
void delete(Object entity):刪除指定持久化執行個體
deleteAll(Collection entities):刪除集合內全部持久化類執行個體
find(String ueryString):根據HL查詢字串來返回執行個體集合
findByNameduery(String ueryName):根據命名查詢返回執行個體集合
get(Class entityClass, Serializable id):根據主鍵載入特定持久化類的執行個體
save(Object entity):儲存新的執行個體
saveOrUpdate(Object entity):根據執行個體狀態,選擇儲存或者更新
update(Object entity):更新執行個體的狀態,要求entity是持久狀態
setMaxResults(int maxResults):設定分頁的大小
常用方法執行個體:
查詢:
//通過HibernateTemplate的find方法返回Person的全部執行個體 -->返回是list類型
return getHibernateTemplate().find("from Person");
//帶參數查詢
用這個方法find(String hql,Object para) -->返回是list類型
String hql = "SELECT u.userName FROM User u WHERE u.userName = ?";
List userList=this.getHibernateTemplate().find(hql,user.getUserName());
//根據主鍵返回特定執行個體 -->主鍵查詢 -->返回是物件類型
return (Person)getHibernateTemplate().get(Person.class, new Integer(personid));
return (Person)getHibernateTemplate().load(Person.class, new Integer(personid));
//儲存的Person執行個體
getHibernateTemplate().saveOrUpdate(person);
//刪除Person執行個體的主鍵
//先載入特定執行個體
Object p = getHibernateTemplate().load(Person.class, new Integer(personid));
//刪除特定執行個體
getHibernateTemplate().delete(p);
Hibernate的主鍵產生器generator說明
1、如果主鍵欄位為自增類型。
那麼對應的.hbm.xml檔案中的id欄位的xml聲明,
應該這麼寫:
<generator class="native" />
例如:
<id column="user_id" name="Id" type="integer" >
<generator class="native" />
</id>
2、如果主鍵欄位不設定為自增,但是是int型的。
可以使用increment,由hibernate產生主鍵。
<generator class="increment" />
不過這種方法,對於並發量大的應用,似乎最好不要採用。
3、如果使用uuid.hex產生的隨機32位元最為主鍵。
那麼資料庫的id欄位類型為char,長度為32
hbm.xml中寫為: <generator class="uuid.hex" />
另外,uuid.string也是功能類似。
uuid.hex產生的是32位的16進位數位字串。
而uuid.string產生的是16個字元長的任意ASCII字元組成的字串
見參考:
uuid.hex
用一個128-bit的UUID演算法產生字串類型的標識符。在一個網路中唯一(使用了IP地址)。UUID被編碼為一個32位16進位數位字串。
uuid.string
使用同樣的UUID演算法。UUID被編碼為一個16個字元長的任意ASCII字元組成的字串。不能使用在PostgreSQL資料庫中