Strategy for manage Hibernate Session - java

I develop a java web app using Hibernate. Here are some code :
hibernate.cfg.xml
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&connectionCollation=utf8mb4_general_ci</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!--<property name="hibernate.connection.autocommit">true</property>-->
<property name="hibernate.current_session_context_class">thread</property>
BaseDAO.class
public class BaseDAO {
public Session getSession() {
return HibernateUtil.getSessionFactory().openSession();
}
}
I write a generic class for insert, update, delete, find
public class GenericDAO<T, K extends Serializable> extends BaseDAO implements IGenericDAO<T, K> {
private Class<T> type;
protected Class<T> getType() {
return this.type;
}
protected String getClassName() {
return type.getName();
}
#SuppressWarnings("unchecked")
public GenericDAO() {
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
type = (Class<T>) pt.getActualTypeArguments()[0];
}
#Override
public K save(T t) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
K k = (K) session.save(t);
tran.commit();
return k;
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
return null;
}
#Override
public void saveOrUpdate(T t) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
session.saveOrUpdate(t);
tran.commit();
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
}
#Override
public void update(T t) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
session.update(t);
tran.commit();
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
}
#Override
public void delete(T t) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
session.delete(t);
tran.commit();
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
}
#Override
public void delete(K k) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
T t = (T) session.get(type, k);
session.delete(t);
tran.commit();
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
}
#SuppressWarnings("unchecked")
#Override
public T find(K id) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
T t = (T) session.get(type, id);
tran.commit();
return t;
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
return null;
}
#SuppressWarnings("unchecked")
#Override
public List<T> findAll() {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
Query query = session.createQuery("from " + type.getSimpleName());
List<T> list = query.list();
tran.commit();
return list;
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
return new ArrayList<>();
}
#SuppressWarnings("unchecked")
#Override
public List<T> findAllWithOrder(String column, String orderType) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
if (orderType == null && orderType.equals("")) {
orderType = "ASC";
}
Query query = session.createQuery(
String.format("from %s order by %s %s", type.getSimpleName(),
column, orderType));
tran.commit();
return query.list();
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
return new ArrayList<>();
}
}
You can see, I don't close session after each method. This code work fine for insert, update and find . But when I want to delete a object :
TblUser user = (TblUser)find(id);
delete(user);
It's throw exception because I use two session for this function.
Then try to close session in each method :
finally{
session.close();
}
Now I can delete object but I can't use lazy load because session has closed for each transaction.
So, how I can manage session to overcome these situation !!!

Since you have activated the property:
<property name="hibernate.current_session_context_class">thread</property>
why don't you use:
public Session getSession() {
return HibernateUtil.getSessionFactory().getCurrentSession();
}
Instead of opening a new session? By doing this, you don't need to worry about closing your session since Hibernate will close it when you close your sessionFactory.
But be aware that this is not thread safe so if you are working in a multi-thread environment, this is not a good option.

Related

IllegalStateException: Session/EntityManager is closed

I'm trying to implement his Java code with Hibernate in order to make SQL queries:
public List<AttendeeModel> getListOfCds(int firstRow, int rowCount) {
List<AttendeeModel> cdList = null;
try {
session.beginTransaction();
Criteria criteria = session.createCriteria(AttendeeModel.class);
criteria.setFirstResult(firstRow);
criteria.setMaxResults(rowCount);
if (criteria != null) {
cdList = (List<AttendeeModel>) criteria.list();
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
return cdList;
}
public int countRows() {
try {
session.beginTransaction();
Criteria criteria = session.createCriteria(AttendeeModel.class);
if (criteria != null) {
return criteria.list().size();
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
return 0;
}
But for some reason I get this error:
java.lang.IllegalStateException: Session/EntityManager is closed
Do you know how I can fix this issue?
From your code it is unclear where session is decleared and how it is populated. Given that this is done somehow correctly, I suspect that missing transaction commit/rollback before return in countRow leads to the exception, try:
public int countRows() {
int size = 0;
try {
session.beginTransaction();
Criteria criteria = session.createCriteria(AttendeeModel.class);
if (criteria != null) {
size = criteria.list().size();
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
return size;
}

Hibernate doesn't close connections/sessions on DB

I have a problem using Hibernate. Each time I call a method that performs a query or update on the database, hibernate opens a session in the database and then does not close. I've tried everything, but actually every time it's called em.getTransaction.begin (); It creates a session in Oracle bd and does not close anymore.
Below is the details of my code (persistence.xml, GenericDAO, etc.)
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="FilaTrello" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>integration.wcc.model.Chamado</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:#//10.ip.aqui/xxxint.xxx.com.br"/>
<property name="javax.persistence.jdbc.user" value="x_SUPORTE"/>
<property name="javax.persistence.jdbc.password" value="x_SUPORTE"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle9iDialect"/>
<property name="hibernate.connection.shutdown" value="true"/>
<!-- <property name="hibernate.hbm2ddl.auto" value="none"/> -->
<property name="hibernate.synonyms" value="true"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="false"/>
</properties>
</persistence-unit>
</persistence>
GenericDAO:
package integration.wcc.dao;
import javax.persistence.*;
import javax.persistence.criteria.CriteriaQuery;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
abstract class GenericDAO<T> implements Serializable {
private static final long serialVersionUID = 1L;
private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("FilaTrello");
private EntityManager em = emf.createEntityManager();;
private Class<T> entityClass;
public void beginTransaction() {
em.clear();
em.getTransaction().begin();
}
public void commit() {
em.getTransaction().commit();
}
public void rollback() {
em.getTransaction().rollback();
}
public void closeTransaction() {
em.close();
}
public void commitAndCloseTransaction() {
commit();
closeTransaction();
}
public void flush() {
em.flush();
}
public void joinTransaction() {
em = emf.createEntityManager();
em.joinTransaction();
}
public GenericDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
public void save(T entity) {
em.persist(entity);
}
public void delete(Object id, Class<T> classe) {
T entityToBeRemoved = em.getReference(classe, id);
em.remove(entityToBeRemoved);
}
public T update(T entity) {
return em.merge(entity);
}
public T find(int entityID) {
return em.find(entityClass, entityID);
}
public T findL(Long entityID) {
return em.find(entityClass, entityID);
}
public T findReferenceOnly(int entityID) {
return em.getReference(entityClass, entityID);
}
// Using the unchecked because JPA does not have a
// em.getCriteriaBuilder().createQuery()<T> method
#SuppressWarnings({"unchecked", "rawtypes"})
public List<T> findAll() {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return em.createQuery(cq).getResultList();
}
// Using the unchecked because JPA does not have a
// query.getSingleResult()<T> method
#SuppressWarnings("unchecked")
protected T findOneResult(String namedQuery, Map<String, Object> parameters) {
T result = null;
try {
Query query = em.createNamedQuery(namedQuery);
// Method that will populate parameters if they are passed not null and empty
if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}
result = (T) query.getSingleResult();
} catch (NoResultException e) {
System.out.println("No result found for named query: " + namedQuery);
} catch (Exception e) {
System.out.println("Error while running query: " + e.getMessage());
e.printStackTrace();
}
return result;
}
#SuppressWarnings("unchecked")
protected List<T> findListResult(String namedQuery, Map<String, Object> parameters) {
List<T> result = null;
try {
Query query = em.createNamedQuery(namedQuery);
// Method that will populate parameters if they are passed not null and empty
if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}
//result = (T) query.getSingleResult();
result = (List<T>) query.getResultList();
} catch (NoResultException e) {
System.out.println("No result found for named query: " + namedQuery);
} catch (Exception e) {
System.out.println("Error while running query: " + e.getMessage());
e.printStackTrace();
}
return result;
}
private void populateQueryParameters(Query query, Map<String, Object> parameters) {
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
}
}
}
Access DAO class:
public class FilaChamadoDAO extends GenericDAO<FilaChamado> {
private static final long serialVersionUID = 1L;
public FilaChamadoDAO() {
super(FilaChamado.class);
}
public List<FilaChamado> findTicketsByFila(int idFila,String listType) {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("filaNumber", idFila);
parameters.put("listParam", listType);
return super.findListResult(FilaChamado.FIND_TICKETS_FILA_BY_FILA, parameters);
}
Ai eu tenho uma classe facade para cada Model meu, que faz a interface de acesso ao DAO:
I have a Facade class for each Model class, which makes the DAO access interface:
public class FilaChamadoFacade {
private FilaChamadoDAO FilaChamadoDAO = new FilaChamadoDAO();
public List<FilaChamado> listAll() {
FilaChamadoDAO.beginTransaction();
List<FilaChamado> result = FilaChamadoDAO.findAll();
FilaChamadoDAO.closeTransaction();
return result;
}
public List<FilaChamado> findTicketsByFila(int idFila,String listaDestino) {
List<FilaChamado> result = null;
try {
FilaChamadoDAO.beginTransaction();
result = FilaChamadoDAO.findTicketsByFila(idFila, listaDestino);
FilaChamadoDAO.flush();
} catch (HibernateException e) {
if (FilaChamadoDAO != null) {
FilaChamadoDAO.rollback();
}
e.printStackTrace();
} finally {
FilaChamadoDAO.closeTransaction();
}
return result;
}
When I call ListAll() function or any namedWaury, I can't anyway close these opened connections.
I've made a simple test in a Main class:
public class TestNamedQuery {
public static void main(String[] args) {
TrelloUser trelloU = new TrelloUser();
TrelloUserFacade facade2 = new TrelloUserFacade();
List<TrelloUser> trelloUsers1 = new ArrayList<TrelloUser>();
trelloUsers1 = facade2.listAll();
for (TrelloUser trelloUser : trelloUsers1) {
if(trelloUser.getUserToken() != null) {
System.out.println("Selectss do usuario: "+trelloUser.getUserName());
ChamadoCard cards = new ChamadoCard();
cards.InsereChamado(trelloUser);
}
}
}
}
As you can see, in my facade class every time I start a transaction ,I close it, but this does not happen in Oracle, where a session is created for each beginTransaction of my EntityManager.
After a lot of attempts, I just found a post saying that I have to commitor rollback every time I call beginTransaction()method to my Entity Manager.
So I change my code like this in theGenericDA.javaclass:
public void closeTransaction() {
em.getTransaction().commit();
em.close();
}
I still trying to understand why Hibernate forces me to COMMIT a transaction even in a query statement, and I think that i can earn a great performance without do it.
But that change work like a charm for me.

Hibernate Junit H2 In memory database test case changing fields in the development db

I have developed a project using Hibernate. I am trying to test it using Junit with H2 in memory db but the test case is creating fields in the db that I am using it for development.
Here is my code :
UserDAO.java
public interface UserDAO {
public void addUser(String username, String password);
public List<String> getUsers();
}
UserDAOImpl.java
public class UserDAOImpl implements UserDAO {
public static final Logger LOG = LoggerFactory.getLogger(UserDAOImpl.class);
private static Session session;
private static void beginSession() {
session = DbUtils.getSessionFactory().openSession();
session.beginTransaction();
}
#Override
public void addUser(String username, String password) {
String encryptedPassword = Utils.encrypt(password);
User user = new User(username, encryptedPassword);
beginSession();
try {
session.save(user);
System.out.println(user.getPassword());
session.getTransaction().commit();
} catch (SQLGrammarException e) {
session.getTransaction().rollback();
LOG.error("Cannot save user", e);
} finally {
session.close();
}
}
#Override
public List<String> getUsers() {
beginSession();
List<String> results = new ArrayList<String>();
String hql = "select username from User";
Query query = null;
try {
query = session.createQuery(hql);
results = query.list();
} catch (HibernateException e) {
LOG.error("Cannot execute query", e);
}
return results;
}
}
Files for test cases
SessionFactoryRule.java
public class SessionFactoryRule implements MethodRule {
private SessionFactory sessionFactory;
private Transaction transaction;
private Session session;
#Override
public Statement apply(final Statement statement, FrameworkMethod method, Object test) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
sessionFactory = createSessionFactory();
createSession();
beginTransaction();
try {
statement.evaluate();
} finally {
shutdown();
}
}
};
}
private void shutdown() {
try {
try {
try {
transaction.rollback();
} catch (Exception ex) {
ex.printStackTrace();
}
session.close();
} catch (Exception ex) {
ex.printStackTrace();
}
sessionFactory.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private SessionFactory createSessionFactory() {
Configuration configuration = new Configuration().configure();
configuration.addAnnotatedClass(User.class)
.addAnnotatedClass(Message.class);
configuration.setProperty("hibernate.dialect",
"org.hibernate.dialect.H2Dialect");
configuration.setProperty("hibernate.connection.driver_class",
"org.h2.Driver");
configuration.setProperty("hibernate.connection.url", "jdbc:h2:./data/db");
configuration.setProperty("hibernate.hbm2ddl.auto", "create");
SessionFactory sessionFactory = configuration.buildSessionFactory();
return sessionFactory;
}
public Session createSession() {
session = sessionFactory.openSession();
return session;
}
public void commit() {
transaction.commit();
}
public void beginTransaction() {
transaction = session.beginTransaction();
}
public Session getSession() {
return session;
}`
Here is my test case
UserDAOTest.java
public class UserDAOTest {
#Rule
public final SessionFactoryRule sf = new SessionFactoryRule();
#Test
public void testAddUser() {
Session session = sf.getSession();
UserDAOImpl userDAOImpl = new UserDAOImpl();
String username = "stackoverflow";
String password = "testing";
userDAOImpl.addUser(username, password);
}
}
This test case is updating the fields username and password in the db that I am using while development. How can I stop it and use h2 in-memory db for testing.
You have session = DbUtils.getSessionFactory().openSession() in the UserDAOImpl. This is the reason of using a development database. Your SessionFactoryRule is not used at all.
So what you can to do.
The best choice is use to Spring for Hibernate configuration and unit testing.
Other option is to set sessionFactory to the UserDAOImpl using constructor.
Also, using static here is a really very very bad idea
private static Session session;

Hibernate have to wait for a few seconds before I can get the object that I just created

With this session handler:
public class SessionHandler {
private static SessionFactory DBContext;
static {
try {
DBContext = HibnerateConfiguration.config().buildSessionFactory();
}
catch(Throwable t) {
throw new ExceptionInInitializerError(t);
}
}
/*
* Returns a session anyway. If currently no session exist, open a new one;
* If there is a current session, use the existing one.
*/
#Override
public Session getSession() {
try {
return DBContext.getCurrentSession();
}
catch (HibernateException he) {
logger.error("session already exist.");
return DBContext.getCurrentSession();
}
}
public void close() {
DBContext.close();
}
}
and the following create and get methods:
public Serializable create(T type_entity) {
Session session = getSessionHandler().getSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Serializable result = session.save(type_entity);
tx.commit();
return result;
} catch (HibernateException ex) {
ex.printStackTrace();
if (tx!=null) tx.rollback();
throw ex;
} finally {
getSessionHandler().close();
}
}
#SuppressWarnings("unchecked")
public T get(Serializable id) throws InvalidRequestException {
Session session = getSessionHandler().getSession();
Transaction tx = session.beginTransaction();
tx.commit();
try {
Object obj = session.get(_classtype, id);
if (obj == null) {
throw new InvalidRequestException(String.format("requested object with id %s does not exist.", id));
} else {
return (T)obj;
}
} catch(HibernateException ex) {
ex.printStackTrace();
if (tx!=null) tx.rollback();
throw ex;
} finally {
getSessionHandler().close();
}
}
When I create an object that returns me id = 4, and if immediately I make a request on browser that eventually ask for the new object of id 4, I have to wait for a few seconds (last time I tried is > 3 seconds).
When the id is returned from the create, the data should already exist. However the get returns null. I highly suspect the get is using the old cache which then is updated every a few seconds, but I have no idea how to fix it.
Let me know if any info is required and I am happy to provide them.

Why do I cannot user createCriteria method which I define in ManagerBase class?

I dont know why i cannot call getAll() class in ManagerBase class from UserDAO, but with other class it still be ok
Hibernate code here
protected Session getCurrentSession() throws Exception {
if (session == null){ //check session null
if (sessionFactory == null){ //build sessionFactory if it null
if(sessionFactoryConfigPath == null || sessionFactoryConfigPath.equals("")){
sessionFactory = new Configuration().configure().buildSessionFactory();
}else{
sessionFactory = new Configuration().configure(this.sessionFactoryConfigPath).buildSessionFactory();
}
}
session = sessionFactory.getCurrentSession();
}
return session;
}
ManagerBase code
public abstract class ManagerBase<T> extends HibernateUtil {
private Class<T> persistentClass;
public ManagerBase() throws Exception {
super();
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments().getClass();
}
public ManagerBase(String sessionFactoryConfigPath) throws Exception {
super(sessionFactoryConfigPath);
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments().getClass();
}
public Class<T> getPersistentClass() {
return this.persistentClass;
}
public List<T> getAll() {
List<T> list = null;
try {
beginTransaction();
list = getCurrentSession().createCriteria(this.persistentClass).list();
commitAndClose();
} catch (Exception ex) {
System.out.println("getAll Error \n" + ex);
}
return list;
}
UserDAO code here.....
code
public class UserDAO extends ManagerBase<User> {
public UserDAO() throws Exception {
}
public List<User> getAllUser() {
try {
List<User> user = getAll();
return user;
} catch (Exception ex) {
System.out.println("Get All User Error \n" + ex);
return null;
}
}
}
Any body please help me, in the console board that show only Begin and commit and it doesnt has any HQL code.

Categories