3
I am developing a Java application, and I am doubtful where to close the Entity Manager.
I have an abstract class AbstractService<T>
which is extended by all entities of the system, and this class has the persistence methods.
In any Servlet, I instate one or more service classes (each entity class has a service class, for example the service class Category_DTO
and its class of service CategoryServiceImpl
), which contains queries of search, and at the same time extends AbstractService<T>
My doubt is the best place to close the entityManager, em.close()
.
I thought of closing in the very Servlet, at the end of it, using the instance of DocumentServiceImpl
with dsi.closeTX()
, but I found it a bit tricky (remembering that a Servlet can contain several service classes, and I would have to close the entitymanager of each one that extended AbstractService
and created the entitymanager).
I will send a JSP, with an example code that is used in Servlets, where I will return all categories. At the end of JSP I am closing the entitymanager, but I believe that the correct thing would be to close in the persistence class and not in Servlet.
Follows the code:
Entity:
package freedom.technology.domain.document;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import freedom.technology.enus.CategoryType;
@Entity
@Table(name = "FRE_CL_GED_CATEGORY")
@NamedQueries({
@NamedQuery(name="Category_DTO.findAllCategories", query="SELECT a FROM Category_DTO a WHERE :search is null OR (a.id LIKE :search OR a.description LIKE :search) ORDER BY a.description ASC"),
@NamedQuery(name="Category_DTO.findAllCategoriesDESC", query="SELECT a FROM Category_DTO a WHERE :search is null OR (a.id LIKE :search OR a.description LIKE :search) ORDER BY a.description DESC"),
@NamedQuery(name="Category_DTO.findAllCategoriesByType", query="SELECT a FROM Category_DTO a WHERE (:search is null OR (a.id LIKE :search OR a.description LIKE :search)) AND a.type = :type ORDER BY a.description ASC"),
@NamedQuery(name="Category_DTO.findAllCategoriesByTypeDESC", query="SELECT a FROM Category_DTO a WHERE (:search is null OR (a.id LIKE :search OR a.description LIKE :search)) AND a.type = :type ORDER BY a.description DESC"),
@NamedQuery(name="Category_DTO.getNumberOfCategories", query="SELECT COUNT(*) FROM Category_DTO"),
@NamedQuery(name="Category_DTO.getNumberOfCategoriesBySearchCondition", query="SELECT COUNT(*) FROM Category_DTO a WHERE :search is null OR (a.id LIKE :search OR a.description LIKE :search) ORDER BY a.id DESC"),
})
public class Category_DTO {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
private Integer id;
@Column(name="description")
private String description;
@Column(name="type")
private CategoryType type;
public Integer getId() {
return id;
}
public String getDescription() {
return description;
}
public CategoryType getType() {
return type;
}
public void setId(Integer id) {
this.id = id;
}
public void setDescription(String description) {
this.description = description;
}
public void setType(CategoryType type) {
this.type = type;
}
}
Class that returns records based on a specific search:
package freedom.technology.service.document.impl;
import java.util.List;
import javax.persistence.TypedQuery;
import freedom.technology.domain.document.Category_DTO;
import freedom.technology.domain.document.Subject_DTO;
import freedom.technology.enus.CategoryType;
import freedom.technology.exception.ExceptionType;
import freedom.technology.exception.FREBDCoreException;
import freedom.technology.service.AbstractService;
import freedom.technology.service.document.api.CategoryService;
public class CategoryServiceImpl extends AbstractService<Category_DTO> implements CategoryService {
@Override
protected Class<Category_DTO> getEntityClass() {
return Category_DTO.class;
}
@Override
public List<Category_DTO> findAllCategories(Integer pageSize, Integer pageNumber, String searchCondition, String orderBy)
throws FREBDCoreException {
List<Category_DTO> result = null;
if (pageSize == null || pageNumber == null){
throw new FREBDCoreException(ExceptionType.NULLPOINTER, "Parametro null: pageSize/pageNumber");
}
try {
TypedQuery<Category_DTO> query = em.createNamedQuery("Category_DTO.findAllCategories", Category_DTO.class);
if(orderBy.equals("DESC")){
query = em.createNamedQuery("Category_DTO.findAllCategoriesDESC", Category_DTO.class);
}
if(searchCondition != null) {
query.setParameter("search", "%"+searchCondition+"%");
} else {
query.setParameter("search", null);
}
query.setFirstResult(pageSize*pageNumber);
query.setMaxResults(pageSize);
result = query.getResultList();
} catch(Exception e) {
e.printStackTrace();
throw new FREBDCoreException(ExceptionType.NORESULT, "findAllCategories");
}
return result;
}
@Override
public List<Category_DTO> findAllCategoriesByType(Integer pageSize, Integer pageNumber, CategoryType type, String searchCondition, String orderBy)
throws FREBDCoreException {
List<Category_DTO> result = null;
if (pageSize == null || pageNumber == null){
throw new FREBDCoreException(ExceptionType.NULLPOINTER, "Parametro null: pageSize/pageNumber");
}
try {
TypedQuery<Category_DTO> query = em.createNamedQuery("Category_DTO.findAllCategoriesByType", Category_DTO.class);
if(orderBy.equals("DESC")){
query = em.createNamedQuery("Category_DTO.findAllCategoriesByTypeDESC", Category_DTO.class);
}
if(searchCondition != null) {
query.setParameter("search", "%"+searchCondition+"%");
} else {
query.setParameter("search", null);
}
if(type != null) {
query.setParameter("type", type);
} else {
query.setParameter("type", null);
}
query.setFirstResult(pageSize*pageNumber);
query.setMaxResults(pageSize);
result = query.getResultList();
} catch(Exception e) {
e.printStackTrace();
throw new FREBDCoreException(ExceptionType.NORESULT, "findAllCategoriesByType");
}
return result;
}
@Override
public int getNumberOfCategories() throws FREBDCoreException {
int result;
try {
TypedQuery<Long> query = em.createNamedQuery("Category_DTO.getNumberOfCategories", Long.class);
result = query.getSingleResult().intValue();
} catch(Exception e) {
result = 0;
}
return result;
}
@Override
public int getNumberOfCategories(String searchCondition)
throws FREBDCoreException {
int result;
try {
TypedQuery<Long> query = em.createNamedQuery("Category_DTO.getNumberOfCategoriesBySearchCondition", Long.class);
if(searchCondition != null) {
query.setParameter("search", "%"+searchCondition+"%");
} else {
query.setParameter("search", null);
}
result = query.getSingleResult().intValue();
} catch(Exception e) {
result = 0;
}
return result;
}
}
Persistence class:
package freedom.technology.service;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import freedom.technology.exception.ExceptionType;
import freedom.technology.exception.FREBDCoreException;
import freedom.technology.utils.PersisteUtils;
public abstract class AbstractService<T> implements GenericService<T> {
private static EntityManagerFactory factory = PersisteUtils.getEntityManagerFactory();
protected EntityManager em;
protected abstract Class<T> getEntityClass();
public AbstractService() {
em = factory.createEntityManager();
}
public void beginTX(){
em.getTransaction().begin();
}
public void commitTX(){
em.getTransaction().commit();
}
public void closeTX(){
em.close();
}
public void rollback(){
em.getTransaction().rollback();
}
public T findById(Integer id){
T result = null;
try {
em.getTransaction().begin();
result = em.find(this.getEntityClass(), id);
em.getTransaction().commit();
} catch(Exception e) {
e.printStackTrace();
}
return result;
}
public void persist(T entity) {
try {
em.getTransaction().begin();
em.persist(entity);
em.getTransaction().commit();
} catch (Exception ex) {
ex.printStackTrace();
em.getTransaction().rollback();
}
}
public void merge(T entity) {
try {
em.getTransaction().begin();
em.merge(entity);
em.getTransaction().commit();
} catch (Exception ex) {
ex.printStackTrace();
em.getTransaction().rollback();
}
}
public void removeObject(T entity) {
try {
em.getTransaction().begin();
em.remove(entity);
em.getTransaction().commit();
} catch (Exception ex) {
ex.printStackTrace();
em.getTransaction().rollback();
}
}
}
Jsp example, closing entityManager at the end:
<%@page import="freedom.technology.domain.document.Category_DTO"%>
<%@page import="freedom.technology.service.document.api.CategoryService"%>
<%@page import="freedom.technology.service.document.impl.CategoryServiceImpl"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<%
CategoryService ds = new CategoryServiceImpl();
List<Category_DTO> listCategory = ds.findAllCategories(100, 0, null, null);
for(Category_DTO category : listCategory){
out.print("Categorias:");
out.print("<br><br>");
out.print("Categoria: " + category);
out.print("<br>");
}
ds.closeTX();
%>
</body>
</html>
Related tip, I suggest rethinking this class
AbstractService
, the way this hierarchy will grow and expand throughout your system, in the near future it will be a real nightmare.– Juliano Alves