GWT RequestFactory:如何每个请求使用单个EntityManager

发布于 2024-10-17 04:10:09 字数 420 浏览 4 评论 0原文

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

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

是否有一种简单的方法可以确保在给定的 ServletRequest 中使用单个 EntityManager,而无需求助于完整的 J2EE/CDI?如果必须的话,我会采取这种方式,但我希望让事情变得简单,特别是因为我想继续使用 GWT 附带的轻量级开发服务器。

In order to get RequestFactory to persist attached entities, I need to ensure that I use the same EntityManager for each request.

I cobbled together my own Factory class for this based on a ThreadLocal implementation, but I'm unsure how to properly release resources (e.g. how to know that the request has finished and call close()).

Is there a simple way to ensure that a single EntityManager is used throughout a given ServletRequest without resorting to full-on J2EE/CDI? I'll take that route if I must, but I was hoping to keep things simple, especially since I'd like to continue using the lightweight development server that comes with GWT.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

温暖的光 2024-10-24 04:10:09

以下是我根据 GWT Google 群组鲍勃V

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

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

但到目前为止,这段代码似乎与 RequestFactory 配合得很好。强烈欢迎改进建议。

注意:这一经验告诉我,可能值得转向全面的 CDI,而不是尝试实现诸如此类的部分内容。我只是在这个项目期间没有时间进行这样的移动。

Here is what I ultimately came up with, based on feedback from the GWT Google Group, and BobV.

Create a thread-local holder for the EntityManager; reference this in your entities when they need to get an 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);
    }
}

Then create a filter that will set the initial EntityManager for the request:

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();
        }

    }
}

Then apply the filter to the /gwtRequest URL pattern:

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

Note that there is a flaw here- an EntityManager is created for each request that goes through this servlet, whether it's used by your underlying code or not. It could probably stand to be made more robust and somehow lazily create the EntityManager (and the transaction) only when requested.

But so far this code seems to work well with RequestFactory. Suggestions for improvements highly welcomed.

Note: this experience has taught me that it's probably worth moving to full-on CDI rather than trying to implement pieces of it such as this. I just didn't have the time available for such a move during this project.

暖伴 2024-10-24 04:10:09

DynaTableRf 示例应用程序通过添加 servlet 过滤器以在其 web.xml 文件。或者,您可以将 RequestFactoryServlet 并重写其 doPost() 方法来拆除 EntityManager 中的>finally 当 super.doPost() 返回时阻塞。

The DynaTableRf sample app does something similar by adding a servlet filter to set up a persistence context in its web.xml file. Alternatively, you could subclass the RequestFactoryServlet and override its doPost() method to tear down the EntityManager in a finally block when super.doPost() returns.

笙痞 2024-10-24 04:10:09

如果您使用 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>

If you're using Spring you only need to add the an OpenEntityManagerInView servlet filter to your 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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文