如何在jersey / hk2应用程序中正确配置EntityManager?
我有一个使用JPA持久性的jersey-2 / hk2应用程序。 EntityManager
在启动时就像这样绑定
public MyApplication() { // ... register(new AbstractBinder() { @Override public void configure() { bindFactory(EmFactory.class) .to(EntityManager.class) .in(RequestScoped.class); } }); }
与工厂类一样
public class EmFactory implements Factory { private static final String PERSISTENCE_UNIT = "unit"; private EntityManagerFactory emf; private CloseableService closeableService; @Inject public EmFactory(@Named(PERSISTENCE_UNIT) String persistenceUnit, CloseableService closeableService) { emf = Persistence.createEntityManagerFactory(persistenceUnit); this.closeableService = closeableService; } @Override public EntityManager provide() { final EntityManager entityManager = emf.createEntityManager(); closeableService.add(new Closeable() { @Override public void close() throws IOException { if(entityManager.isOpen()) { entityManager.close(); } } }); return entityManager; } @Override public void dispose(EntityManager entityManager) { if(entityManager.isOpen()) { entityManager.close(); } } }
这可以工作,但是对于每个请求,我在日志中收到有关已注册的EntityManager的警告:
HHH000436: Entity manager factory name (unit) is already registered. \ If entity manager will be clustered or passivated, specify a unique \ value for property 'hibernate.ejb.entitymanager_factory_name'
我究竟做错了什么? 在jersey-2 / hk2应用程序中初始化EntityManager的正确方法是什么?
一种选择是,不是在EMFactory
中创建新的EntityManagerFactory
(在请求范围内),您可以为EntityManagerFactory
创建一个单独的工厂,然后将EntityManagerFactory
注入EMFactory
。
public class EMFFactory implements Factory { private final EntityManagerFactory emf; public EMFFactory (){ emf = Persistence.createEntityManagerFactory(persistenceUnit); } public EntityManagerFactory provide() { return emf; } ... } public class EMFactory implements Factory { private final EntityManager em; @Inject public EMFactory (EntityManagerFactory emf){ em = emf.createEntityManager(); } public EntityManager provide() { return em; } ... }
没有测试过这个确切的实现,但它看起来应该是这样的。 我以前用过这种模式。
register(new AbstractBinder() { @Override public void configure() { bindFactory(EMFFactory.class).to(EntityManagerFactory.class).in(Singleton.class); bindFactory(EMFactory.class).to(EntityManager.class).in(RequestScoped.class); } });
UPDATE
关于上述示例需要注意的一点是它不会清理资源,即EntityManager
应该关闭; 它不会自行关闭。 我们需要覆盖Factory
类中的dispose
方法,但根据我的经验,Jersey从不调用它。
我们可以做的是将EntityManager
添加到[ CloseableService
] [1]
public class EMFactory implements Factory { private final EntityManagerFactory emf; private final CloseableService closeService; @Inject public EMFactory (EntityManagerFactory emf, CloseableService closeService){ this.emf = emf; this.closeService = closeService; } public EntityManager provide() { final EntityManager em = emf.createEntityManager(); this.closeService.add(new Closeable(){ @Override public void close() { em.close(); } }); return em; } ... }
这样就确保在请求结束时关闭EntityManager
。