Comment configurer correctement un EntityManager dans une application jersey / hk2?

j'ai une application jersey-2 / hk2 qui utilise la persistance JPA. Le EntityManager est lié au démarrage comme ceci

public MyApplication() {
    // ...
    register(new AbstractBinder() {
        @Override
        public void configure() {
          bindFactory(EmFactory.class)
            .to(EntityManager.class)
            .in(RequestScoped.class);
        }
    });
}

, la classe d'usine étant

public class EmFactory implements Factory<EntityManager> {

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

cela fonctionne mais ensuite pour chaque requête je reçois un avertissement dans les logs au sujet d'un EntityManager étant déjà enregistré:

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'

Qu'est-ce que je fais de mal? Quelle est la bonne façon d'initialiser un EntityManager dans un jersey-2 / hk2 application?

6
demandé sur Paul Samsotha 2015-01-20 15:07:27

1 réponses

une option est de créer une nouvelle EntityManagerFactory dans le EMFactory (qui est dans une requête scope), vous pouvez créer une usine singleton pour le EntityManagerFactory , puis juste injecter le EntityManagerFactory dans le EMFactory .

public class EMFFactory implements Factory<EntityManagerFactory> {
    private final EntityManagerFactory emf;
    public EMFFactory (){
        emf = Persistence.createEntityManagerFactory(persistenceUnit);
    }
    public EntityManagerFactory provide() {
        return emf;
    }
    ...
}

public class EMFactory implements Factory<EntityManager> {
    private final EntityManager em;

    @Inject
    public EMFactory (EntityManagerFactory emf){
        em = emf.createEntityManager();
    }
    public EntityManager provide() {
        return em;
    }
    ...
}

N'a pas testé cette implémentation exacte, mais ça devrait ressembler à ça. J'ai utilisé ce modèle avant.

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

mise à JOUR

une chose à noter à propos de l'exemple ci-dessus est qu'il ne nettoie pas les ressources, c.-à-d. le EntityManager devrait être proche; il ne se fermera pas lui-même. Il y a une méthode dispose dans la classe Factory que nous devons passer outre, mais d'après mon expérience, ce N'est jamais appelé par Jersey.

ce que nous pouvons faire est d'ajouter le EntityManager à un [ CloseableService ][1]

public class EMFactory implements Factory<EntityManager> {
    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;
    }
    ...
}

de cette façon le EntityManager est assuré pour être fermé à la fin de la demande.

12
répondu Paul Samsotha 2016-07-06 08:51:44