2014-10-07 86 views
2

我有一個現有的項目工作正常,但現在我必須實現一個備份系統執行exery日,並將數據庫轉儲到文件。我想用ScheduledTask解決這個問題,但這意味着有另一個Thread使用Hibernate。春天和休眠:多個連接,線程安全

我的問題:究竟如何讓Hibernate線程安全?

我有以下的代碼 - (摘錄):

在applicationContext.xml中

<bean id="myEmf" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="dbDataSource" /> 
    <property name="packagesToScan" value="redb.main.core.model" /> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> 
    </property> 
    <property name="jpaProperties"> 
     <props> 
      <prop key="hibernate.hbm2ddl.auto">validate</prop> 
      <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop> 
      <!-- <prop key="hibernate.enable_lazy_load_no_trans">true</prop> --> 
     </props> 
    </property> 
</bean> 

<!-- Transaction Management --> 
<tx:annotation-driven transaction-manager="txManager" /> 
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="myEmf" /> 
</bean> 

<bean id="persistenceExceptionTranslationPostProcessor" 
    class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" /> 

這樣我就可以得到EntityManager通過

@PersistenceContext 
protected EntityManager entityManager; 

但是,如果我的理解是正確的,每個Thread需要自己的EntityManagerEntityManagerFactory

如何在其他課程中創建新的EntityManager?我有persistence.xml。我必須創建它嗎?

+1

Spring將注入一個線程綁定'EntityManger'(如文檔中所述)。只要確保你所做的是在一個事務中,這樣就會有一個線程綁定'EntityManager'。你沒有得到一個單獨的線程,每個線程都有它自己的(如果你使用'OpenEntityManagerInViewFilter/-Interceptor',那麼在事務或者請求期間,但在這裏不適用,因爲你需要我們後臺線程)。但是,讓數據庫執行備份而不是嘗試外部化它不是更容易嗎? – 2014-10-07 18:20:20

+1

如果事務沒有開始(假設你有'@ Transactional'),確保你有一個''來啓用事務。還要確保你沒有複製bean實例,在你的'ContextLoaderListener'和'DispatcherServlet'中有'component-scan'可能會導致(取決於設置)重複bean,其中一個被代理並且有事務,另一個不。在過濾器中不應該有一個事務(還),因爲它在其他事務之前執行,過濾器不會啓動事務,而是將一個EntityManager綁定到當前線程。 – 2014-10-08 07:55:56

回答

0

他 - 他。歡迎來到地獄。

主要問題是,春天試圖用基於方面的解決方案來做到這一點。雖然這是錯誤的(或不可破壞的),但在微不足道的情況下它可以工作。

您的問題的一般答案是,EntityManagerFactory可以是軟件中的全局靜態對象,儘管如果我簡單地使用了這個對象,我就會被扔石頭。

默認情況下,spring aop會在應用程序中「編織」部署,通過註釋查找所有數據庫實體類,並封裝其方法以始終提供現有的entitymanager。這是理論。但這不是實踐。

實踐是,你幾乎不能控制究竟會發生什麼。

我做了什麼:有一個名爲org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter的servlet過濾器,它可以爲每個請求打開一個entitymanager,並根據需要刷新/關閉該過濾器。是的,它的名字是關於「意見」的,但它的名字很快就是它的第一個bug:實際上我們不得不稱之爲「requesttransactionfilter」等等。它沒有任何MVC視圖可以做,它正在處理來自servlet容器的http請求實體。

如果你不喜歡在spring應用程序中使用servlet過濾器,那麼也有一個名爲OpenEntityManagerInViewInterceptor的彈簧攔截器也具有非常相似的功能。

以編程方式,您可以通過createEntityManager()方法從EntityManagerFactory生成EntityManager

快樂的谷歌搜索!你正處在一個漫長的道路上。

+1

Spring確保您有一個線程安全的'EntityManager'它只是一個代理,它查找綁定EntityManager的線程或使用EntityManagerFactory創建一個新線程。沒有什麼可怕的,而且它可以在全球範圍內的無數企業應用中發揮作用。沒有涉及編織,也沒有涉及AspectJ。唯一的AOP部分是您需要確保所有內容都在事務內部執行並且可以正常工作。這並不是一個漫長的過程,它只是一個讓你的配置正確的問題,並且從你描述的你沒有的東西開始,並試圖解決它。 – 2014-10-07 18:18:22

+1

'OpenEntityManagerInViewInterceptor'確實與視圖無關,但與請求和處理線程無關。但對於後臺線程來說,它並沒有做任何事情。它是一個'HandlerInterceptor',並且是Spring MVC的一部分,因此綁定到了Web上。後臺線程無用。 – 2014-10-08 05:32:46

+1

@ M.Deinum好吧。給圖書館帶來誤導性的名字是一個小問題還是一個嚴重的問題?如果某些東西根本不起作用(例如,最終的問題:事務/ EntityManager不是以某種方式創建的),那麼你究竟能夠挖掘出什麼_had_ __ __ _ _done_?春天/時間不存在地方責任範式。幾個月以來,我一直在挖掘泉源,並在那裏創造了一些關於那些不是簡單回答的問題。是的,因爲沒有。令人不愉快的春/ a問題的真正答案是:「深入挖掘資源並祈禱」。 – peterh 2014-10-08 07:16:45