为了RequestFactory
到persist attached entities,我需要确保为每个请求使用相同的EntityManager
。
我基于ThreadLocal
实现拼凑了我自己的Factory类,但我不确定如何正确释放资源(例如,如何知道请求已完成并调用close()
)
是否有一种简单的方法可以确保在给定的ServletRequest中使用单个EntityManager而无需使用完整的J2EE / CDI?如果必须的话,我会采取这种方式,但我希望保持简单,特别是因为我想继续使用GWT附带的轻量级开发服务器。
答案 0 :(得分: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 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,而不是试图实现它的一部分。在这个项目期间,我只是没有时间进行这样的行动。
答案 1 :(得分:4)
DynaTableRf示例应用程序通过添加servlet过滤器在其web.xml文件中设置持久性上下文来执行类似操作。或者,您可以继承RequestFactoryServlet并覆盖其doPost()
方法,以便在EntityManager
返回时删除finally
块中的super.doPost()
。
答案 2 :(得分: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>