GWT RequestFactory: how to use single EntityManager per request

江枫思渺然 提交于 2019-12-03 08:53:52

问题


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.


回答1:


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.




回答2:


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.




回答3:


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>


来源:https://stackoverflow.com/questions/4988397/gwt-requestfactory-how-to-use-single-entitymanager-per-request

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!