3

为了持久RequestFactory附加的实体,我需要确保EntityManager对每个请求都使用相同的。

我基于实现拼凑了我自己的工厂类ThreadLocal,但我不确定如何正确释放资源(例如如何知道请求已经完成并调用close())。

有没有一种简单的方法来确保在整个给定的 ServletRequest 中使用单个 EntityManager 而无需求助于完整的 J2EE/CDI?如果必须的话,我会走这条路,但我希望保持简单,特别是因为我想继续使用 GWT 附带的轻量级开发服务器。

4

3 回答 3

6

这是我根据GWT Google GroupBobV的反馈最终得出的结论。

为 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 URL 模式:

<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>

请注意,这里有一个缺陷 - 为通过此 servlet 的每个请求创建一个 EntityManager,无论它是否被您的底层代码使用。它可能会变得更加健壮,并且仅在请求时才以某种方式懒惰地创建 EntityManager(和事务)。

但到目前为止,这段代码似乎与RequestFactory. 非常欢迎提出改进建议。

注意:这个经验告诉我,可能值得转向完整的 CDI,而不是尝试实现这样的部分。在这个项目期间,我只是没有时间进行这样的举动。

于 2011-02-15T16:25:36.593 回答
4

DynaTableRf 示例应用程序通过添加 servlet 过滤器来在其web.xml文件中设置持久性上下文来执行类似的操作。或者,您可以将RequestFactoryServlet子类化并覆盖其方法以在返回时doPost()拆除EntityManagerinfinally块。super.doPost()

于 2011-02-14T14:20:38.137 回答
2

如果您使用 Spring,您只需将 OpenEntityManagerInView servlet 过滤器添加到您的 web.xml。

<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>
于 2012-08-16T06:45:31.273 回答