2011-02-14 52 views
3

爲了獲得RequestFactorypersist attached entities,我需要確保我爲每個請求使用相同的EntityManagerGWT RequestFactory:如何使用每個請求的單個EntityManager

我拼湊自己的工廠類此基礎上ThreadLocal實現,但我不能確定如何正確地釋放資源(例如,如何知道該請求已完成,並調用close())。

是否有一種簡單的方法可以確保在給定的ServletRequest中使用單個EntityManager而無需使用完整的J2EE/CDI?如果必須的話,我會採取這種方式,但我希望保持簡單,特別是因爲我想繼續使用GWT附帶的輕量級開發服務器。

回答

6

基於來自GWT Google Group,BobV的反饋,我最終想到了這一點。

爲EntityManager創建線程本地持有者;在實體引用這個時候他們需要得到一個EntityManager:

public class ThreadLocalEntityManager 
{ 
    private static ThreadLocal<EntityManager> holder = new ThreadLocal<EntityManager>(); 

    private ThreadLocalEntityManager() 
    { 
    } 

    public static EntityManager get() 
    { 
     return holder.get(); 
    } 

    public static void set(EntityManager em) 
    { 
     holder.set(em); 
    } 
} 

然後創建一個過濾器,將設置初始的EntityManager的要求:

public class PersistenceFilter implements Filter 
{ 
    protected static final Logger log = Logger.getLogger(PersistenceFilter.class.getName()); 
    private EntityManagerFactory factory; 

    @Override 
    public void init(FilterConfig filterConfig) throws ServletException 
    { 
     factory = Persistence.createEntityManagerFactory("my_persistence"); 
    } 

    @Override 
    public void destroy() 
    { 
     factory.close(); 
    } 

    @Override 
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 
    { 
     EntityManager em = factory.createEntityManager(); 
     ThreadLocalEntityManager.set(em); 

     EntityTransaction tx = em.getTransaction(); 
     tx.begin(); 

     try 
     { 
      chain.doFilter(req, res); 
      tx.commit(); 
     } 
     catch (Exception e) 
     { 
      tx.rollback(); 
     } 
     finally 
     { 
      log.info("closing EntityManager: " + EMF.entityManager()); 
      em.close(); 
     } 

    } 
} 

然後過濾器適用於/ gwtRequest網址模式:

<filter> 
    <filter-name>PersistenceFilter</filter-name> 
    <filter-class>com.example.PersistenceFilter</filter-class> 
</filter> 

<filter-mapping> 
    <filter-name>PersistenceFilter</filter-name> 
    <url-pattern>/gwtRequest</url-pattern> 
</filter-mapping> 

注意,是有缺陷這裏 - 一個EntityManager爲每個請求創建通過此servlet,無論是使用您的基礎鱈魚是否。它可能會變得更加健壯,並且只是在被請求的時候以某種方式懶惰地創建EntityManager(和事務)。

但到目前爲止,該代碼似乎與RequestFactory很好。改進建議非常受歡迎。

注意:這個經驗告訴我,它可能值得移到全CDI上,而不是試圖實現這樣的部分。在這個項目中,我只是沒有時間做這樣的動作。

+0

我懷疑你會通過這個過濾器有很多請求不需要EntityManager。這正是我所做的,對我來說也是很好的!在appengine上,事務位不起作用,但是在JDO中打開和關閉持久性管理器也很有效。 – 2011-02-21 20:22:31

4

DynaTableRf示例應用程序通過添加一個servlet過濾器在其web.xml文件中設置一個持久性上下文來做類似的事情。或者,您可以對RequestFactoryServlet進行子分類並覆蓋其doPost()方法,以在super.doPost()返回時拆分finally塊中的EntityManager

+0

再次感謝BobV。我正在嘗試servlet過濾器方法。得到了一個EntityManager-per-request的工作,這當然解決了我的RequestFactory問題。但是現在我正在泄漏資源。這總是一些東西。 :-)一旦我發現錯誤,我會回來總結一下。 – 2011-02-15 01:00:06

2

如果您使用的是Spring,只需要在您的web.xml中添加一個OpenEntityManagerInView servlet過濾器。

<filter> 
    <filter-name>entityManagerFilter</filter-name> 
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> 
</filter> 

<filter-mapping> 
    <filter-name>entityManagerFilter</filter-name> 
    <url-pattern>/gwtRequest</url-pattern> 
</filter-mapping>