2013-05-31 30 views
5

在我們的應用程序中,我們使用Spring和Hibernate。將會話對象注入到DAO bean而不是Session Factory?

在所有的DAO類中,我們都有SessionFactory自動連線,並且每個DAO方法都調用getCurrentSession()方法。

問題我有我們爲什麼不能在原型範圍中注入Session對象而不是SessionFactory對象?這將節省我們對getCurrentSession的調用。

我認爲第一種方法是正確的,但尋找具體的情況下,第二種方法會拋出錯誤或可能會有不好的表現?

+0

一個案例閱讀[文檔](http://docs.jboss.org/hibernate/orm/3.5/javadoc/org/hibernate/Session.html),它說'如果會話引發異常,交易必須被回滾並丟棄該會話。在發生異常之後,會話的內部狀態可能與數據庫不一致。' –

+0

您最好注入'javax.persistence.EntityManager',但爲此,您必須堅持使用JPA。 – Lion

回答

3

當您將bean定義爲原型範圍時,會爲每個需要注入的地方創建一個新實例。所以每個DAO都會得到一個不同的Session實例,但是DAO中所有方法的調用最終都會使用同一個會話。由於會話不是線程安全的,因此不應該在多個線程之間共享,這將是一個問題。

對於大多數情況,會話應該是事務範圍,即當事務開始時打開新會話,然後在事務完成後自動關閉。在少數情況下,可能需要擴展才能請求範圍。

如果你想避免使用SessionFactory.currentSession - 那麼你將需要定義你自己的範圍實現來實現它。

這是使用代理已經爲JPA實現的東西。在JPA的情況下,注入EntityManager而不是EntityManagerFactory。有一個新的@PersistenceContext註釋,而不是@Autowired。代理在初始化期間被創建並注入。當調用任何方法時,代理將獲得實際的EntityManager實現(使用與SessionFactory.getCurrentSession類似的東西)並委託給它。

類似的事情也可以爲Hibernate實現,但額外的複雜性是不值得的。在內部調用SessionFactory.getCurrentSession()的BaseDAO中定義getSession方法要簡單得多。使用這個會話的代碼和注入會話是一樣的。

3

注入原型會話意味着您的每個DAO對象將根據定義獲得它自己的會話...另一方面SessionFactory爲您提供了open的權力並可隨意共享會話。

事實上,getCurrentSession將不會在每次調用時打開新的會話......相反,它將重新使用綁定到current session context(例如,線程,JTA Transacion或外部管理的上下文)的會話。

所以我們來考慮一下吧;假設在你的業務層中有一個操作需要讀取和更新幾個數據庫表(這意味着直接或間接地與幾個DAO進行交互)......很常見的情況是否正確?通常當這種操作失敗時,你會想要回滾當前操作中發生的所有事情嗎?那麼,對於這個「特殊」情況,什麼樣的策略看起來合適呢?

  1. 跨越多個會話,每個會話管理他們自己的對象並綁定到不同的事務。
  2. 有一個會話管理與此操作相關的對象...根據您的業務需求劃分事務。

簡而言之,有效共享會話和劃分交易不僅會提高您的應用程序性能,它還是應用程序功能的一部分。

我會深深建議您閱讀Chapter 2Hibernate Core Reference ManualChapter 13更好地理解角色的框架內SessionFactorySessionTransaction戲劇。它還將教授關於工作單元以及流行的會話模式和反模式