I am developing one application and I have started to use CDI
along with JSF
and JPA
. The web container is Tomcat
.
I am very confused about EntityManager
life-cycle in my CDI
beans and I would need a good advise to clear some stuff in my mind.
Generally what I've read is that EntityManager
should be used mainly in a Java EE
container, injecting it using PersistenceContext
annotation. So then the container takes care about its life. However, if you do not use Java EE
container(as Tomcat
), then I need to manage my EntityManager
's life.
Which are my best options now, using Tomcat, CDI, JSF and JPA
?
What I am currently doing now is the following:
public class EntityManagerFactoryProducer {
public static final String TEST = "test";
@Produces
@ApplicationScoped
public EntityManagerFactory create() {
return Persistence.createEntityManagerFactory(TEST);
}
public void destroy(@Disposes
EntityManagerFactory factory) {
factory.close();
}
}
public class EntityManagerProducer {
@Inject
private transient Logger logger;
@Inject
private EntityManagerFactory emf;
@Produces
public EntityManager create() {
return emf.createEntityManager();
}
public void destroy(@Disposes
EntityManager em) {
em.close();
logger.debug(String.format("%s Entity manager was closed", em));
}
}
@Named
@ViewScoped
@Interceptors(LoggingInterceptor.class)
public class ProductBacking implements Serializable {
@Inject
private ProductDAO productDAO;
@ViewScoped
public class ProductDAOImpl implements ProductDAO, Serializable {
private static final long serialVersionUID = 4806788420578024259L;
private static final int MAX_RANDOMIZED_ELEMENTS = 3000;
@Inject
private transient Logger logger;
@Inject
private EntityManager entityManager;
@Override
public List<Product> getSuggestedProducts() {
logger.debug(String.format("%s Entity manager get products", entityManager));
return entityManager.createQuery("SELECT p FROM Product p ORDER BY random()", Product.class).setMaxResults(
MAX_RANDOMIZED_ELEMENTS).getResultList();
}
@Override
public void saveProduct(Product product) {
logger.debug(String.format("%s Entity manager save product", entityManager));
entityManager.getTransaction().begin();
entityManager.merge(product);
entityManager.getTransaction().commit();
}
@PreDestroy
void destroy() {
entityManager.close();
}
}
So basically I am just using plain CDI
to accomplish this.
However, I am not sure if this is standard way of doing it, and what is more important, I do not know how to close the EntityManager
after bean life is over.
As as summary: I end up with many unclosed connections (EntityManager
s), so memory leak.
Can someone help me understand how should I proceed?