在Hibernate4中,Spring4 我想使用sessionFactory.getCurrentSession()
而不是@Transactional
註釋。有什麼辦法可以做到嗎?Hibernate sessionFactory.getCurrentSession()without @Transactional
回答
您可以在不聲明explicit transaction boundary的情況下使用Hibernate,但只能發出SELECT語句,因爲DML語句需要事務。
使用註釋是實現聲明式事務管理的一種方法,但不是唯一的方法。您也可以在xml配置中使用tx
和aop
名稱空間。通過這種方式,您可以使用集中式事務配置,您還可以在通配符中使用通配符。 您可以用相同的方式使用sessionFactory.getCurrentSession()
。只是交易劃分風格發生了變化。
有關更多詳細信息,請參閱Spring reference documentation。
簡單的答案是:是,當然也可以作爲SessionFactory.getCurrentSession()
只是一個接口的方法,這樣你可以寫你自己的實現類,讓你任何你喜歡的Session
。
但是,這可能不是您正在尋找的答案。
我們一直在問自己一個類似的問題:爲什麼使用Spring的事務管理Hibernate的,做我們必須添加@Transactional
我們的所有方法,甚至是那些只SELECT
數據,因此當不需要進行內執行數據庫事務的上下文?
答案並不那麼簡單,但讓我們看一下所涉及的一些管道,看看我們是否可以理解它。
首先,正如在SO上的其他地方所提到的,Session
的想法與交易的想法有着根本的聯繫。在javadoc中提供了Session
接口:
會話的生命週期由邏輯事務的開始和結束限定。 (長事務可能跨越多個數據庫事務。)
和鑽研@Transactional
類的javadoc的證實,它的目的是表明,當代碼應該是「事務上下文」,這是不一定內執行交易的數據庫的上下文。
這也解釋了爲什麼Spring的@Transactional
註釋允許您設置屬性readOnly=true
,但稍後會更多。
再回到Spring4和Hibernate4,當你調用sessionFactory.getCurrentSession()
它實際上執行SessionFactoryImpl
下面的代碼:
public Session getCurrentSession() throws HibernateException {
if (currentSessionContext == null) {
throw new HibernateException("No CurrentSessionContext configured!");
}
return currentSessionContext.currentSession();
}
所以它實際上是推遲到CurrentSessionContext
實現它(除非你使用JTA,你可能不想打開潘多拉的盒子)是由SpringSessionContext
類處理:
@Override
public Session currentSession() throws HibernateException {
Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
if (value instanceof Session) {
return (Session) value;
}
else if (value instanceof SessionHolder) {
SessionHolder sessionHolder = (SessionHolder) value;
Session session = sessionHolder.getSession();
if (!sessionHolder.isSynchronizedWithTransaction() &&
TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, false));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.equals(FlushMode.MANUAL) &&
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
return session;
}
if (this.transactionManager != null) {
try {
if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
Session session = this.jtaSessionContext.currentSession();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new SpringFlushSynchronization(session));
}
return session;
}
}
catch (SystemException ex) {
throw new HibernateException("JTA TransactionManager found but status check failed", ex);
}
}
if (TransactionSynchronizationManager.isSynchronizationActive()) {
Session session = this.sessionFactory.openSession();
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.MANUAL);
}
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, true));
TransactionSynchronizationManager.bindResource(this.sessionFactory, sessionHolder);
sessionHolder.setSynchronizedWithTransaction(true);
return session;
}
else {
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
}
}
,並解釋爲什麼你會看到異常:
無法獲得交易同步會話當前線程的
當你因爲沒有@Transactional
註釋切入點還沒有執行這是不符合@Transactional
爲TransactionSynchronizationManager.isSynchronizationActive()
回報false
註釋的方法調用sessionFactory.getCurrentSession()
這將創建一個同步事務。 (見org.springframework.transaction.interceptor.TransactionInterceptor
獲取更多信息。)
因此,這使我們回到我們的用例,這是我們不希望調用PlatformTransactionManager
的開銷和它的數據庫事務代碼時,我們只需要執行一個SELECT
針對數據庫。實現此目的的簡單方法是不要撥打sessionFactory.getCurrentSession()
,而是直接打開Session
。例如藉此Spring管理代碼:
public class MyHibernateService {
@Autowired
private SessionFactory sessionFactory;
protected Session transactionalSession() {
return sessionFactory.getCurrentSession();
}
protected Session readOnlySession() {
if(TransactionSynchronizationManager.isSynchronizationActive())
return transactionalSession();
Session session = this.sessionFactory.openSession();
session.setFlushMode(FlushMode.MANUAL);
return session;
}
public List<SalixUrl> activeUrls() {
return readOnlySession().createCriteria(SalixUrl.class)
.add(Restrictions.gt("published", LocalDateTime.now()))
.add(Restrictions.lt("removed", LocalDateTime.now()))
.list();
}
@Transactional
public List<SalixUrl> refreshUrls() {
List<SalixUrl> urls = activeUrls();
for(SalixUrl url : urls) {
url.setLastChecked(LocalDateTime.now());
transactionalSession().update(url);
}
}
}
這將允許你打電話myHibernateService.activeUrls()
,而無需一個@Transactional
標註,還myHibernateService.refreshUrls()
你會想經過PlatformTransactionManager
。
如果這段代碼看起來很熟悉,可能是因爲您已經查看了OpenSessionInViewFilter
(或攔截器)的來源,它通常用於緩解LazyLoadingException
s,並且還負責解決很多n + 1問題程序員認爲他們通過使用FetchType.LAZY
來優化他們的ORM模型來定義實體關係,但沒有編寫他們的服務/存儲庫層來實際獲取需要被提取的視圖來生成。
無論如何,你不想使用上面的代碼。相反,你可以使用想要使用@Transactional
註釋,並讓Spring和Hibernate框架決定實際需要什麼類型的數據庫事務。
如果你擔心性能,你有幾種選擇:
否1.你可以使用Spring的@Transactional(readOnly=true)
但請注意,這不是一定一個偉大的想法。我不主張使用javax @Transactional
,因爲它更通用 - 如果你將你的顏色綁定到Spring桅杆上,那麼你可以使用它所提供的。相反,我很警惕,因爲它所做的一切(使用當前實現)都是要求底層數據庫提供者的Connection
對象被標記爲只讀。由於幾個原因,這可能是有問題的。
首先,您的數據庫提供程序可能不支持只讀連接(例如MSSQL服務器的jTDS JDBC驅動程序),因此可能是毫無意義。
第二個原因是由於連接池。如果您使用的數據庫支持只讀連接(如PostgreSQL)和連接池(如C3P0),那麼您並不想將某些連接標記爲只讀,然後將它們返回到池中,然後允許在需要執行數據庫寫入的情況下提供它們。 (我沒有用Hibernate4和Spring4測試過,但是它肯定是Spring3,Hibernate3和C3P0的問題。)
2.使用緩存。通過我們近來可以訪問的硬件,緩存是,可能是的答案,並且您有很多選項可供您使用。您可以爲Hibernate實體配置第二級緩存,並且Spring本身有一個很好的spring-cache模塊,可以緩存服務/存儲庫方法 - 查看如何整合EhCache。
3.寫你自己的數據庫查詢使用JDBC或其他。 Gavin King(Hibernate作者)一直在指出相當長的一段時間,僅僅因爲你使用Hibernate for ORM,你不需要使用它的一切:https://plus.google.com/+GavinKing/posts/LGJU1NorAvY(我不能找到明確的引用,他說「不」 t使用Hibernate的性能SELECT
「但我認爲幾年前我讀了一些東西)。
但有兩個比較重要的問題:
否1.您不應擔心性能。如果你需要,那麼你不應該讀這個,因爲你應該已經知道所有這些了;-)但是忽略了我的表情,不要浪費時間進行原子代碼優化,而是需要像工程師一樣行事,然後看在整個系統中(如Dirk Gently),然後對最有效的方式作出判斷,以儘可能提高您的系統系統。 請記住:協和隊不再飛行的原因有幾個。
否2.您可能不需要再使用SessionFactory
了。 JPA 2和EntityManager
已被設計爲明確使用SessionFactory
不必要的。即使Emmanuel Bernard(另一位Hibernate作者)在幾年前給了我們這樣的建議:http://www.theserverside.com/news/2240186700/The-JPA-20-EntityManager-vs-the-Hibernate-Session-Which-one-to-use
但是你知道什麼:我喜歡SessionFactory
和Hibernate Criteria API以及它的一切。所以我會繼續使用它,直到他們棄用Spring框架對它的支持。因爲,正如我所說的,如果你已經將你的顏色固定在框架上,那麼你可以使用框架提供的所有東西。實際上,抽象的主要優點(即可以將底層ORM或數據庫提供程序替換掉)是您可能不需要擔心的大概是。 (但是,我已經去過那裏了 - 我不得不將中等規模的代碼庫從MSSQL遷移到PostgreSQL,最大的問題不是Spring/ORM層,而是數據庫特定的代碼,如存儲過程和觸發器,事實上以前的開發人員試圖通過使用@Transactional(readOnly=true)
來優化查詢,但不知道MSSQL實際上不支持它,並且在使用PostgreSQL和C3P0時會中斷。是的,我仍然很痛苦。)
- 1. Hibernate在sessionFactory.getCurrentSession()上失敗
- 2. spring-hibernate transactional dont rollback
- 3. hibernate session.flush with spring @transactional
- 4. Hibernate sessionFactory.getCurrentSession()當與Spring一起使用時
- 5. 正確配置嘲笑對Hibernate的SessionFactory.getCurrentSession()
- 6. sessionFactory.getCurrentSession()與@Transactional一起工作,但sessionFactory.openSession()不是
- 7. 區別b/w Hibernate的Sessionfactory.getCurrentSession()和SessionFactory.openSession()
- 8. Hibernate:sessionFactory.openSession()VS sessionFactory.getCurrentSession()
- 9. Junit with HSQL/H2 without Spring/Hibernate
- 10. 用Spring @Transactional管理Hibernate交易
- 11. sessionFactory.getCurrentSession()會導致NullPointerException
- 12. Hibernate懶惰初始化例外與@Transactional
- 13. @Transactional如何影響Hibernate中的當前會話?
- 14. 顯示java.lang.NullPointerException由於sessionFactory.getCurrentSession()
- 15. SessionFactory.getCurrentSession()線程安全嗎?
- 16. Hibernate,Spring,@Transactional - 用try/catch包圍?
- 17. Spring + Hibernate:插入多重記錄和@Transactional
- 18. Spring 4 + HIbernate 4 + Junit @Transactional nativeSQL query
- 19. Hibernate的session.currentSession()與@Transactional錯誤while session.openSession()不
- 20. Autowire SessionFactory在Spring中沒有@Transactional hibernate
- 21. @Transactional不能使用SessionFactory
- 22. 雖然OSIV已配置,sessionFactory.getCurrentSession()會返回不同的會話
- 23. 如何啓用sessionFactory.getCurrentSession休眠濾波器()?
- 24. @Transactional ignored
- 25. @Transactional註解
- 26. OpentransactionPerView而不是@Transactional
- 27. @Transactional不起作用
- 28. detachedcriteria和detachedquery without EntityManager
- 29. JPA without persistence.xml
- 30. Java的Hibernate查詢,異常
我見過的最好的答案...你能幫我解決這個問題嗎?http://stackoverflow.com/questions/38823693/java-more-than-one -DB連接功能於UserTransaction的?我一直在找到這個解決方案,但是我還沒有找到... – GMsoF