Introduction
I have a JavaEE Application which consists in a RESTFul Web Service. This WS is responsible to receive some requests and answer with XMLs. There are services to store and services to capture information of a MySQL DB.
The system was done using APIs like JAX-WS and JAX-B and the framework Hibernate for data persistence.
Problem
When I update, delete or insert anything in my DB, directly or through a service of the WS, and try to see the result through a service, the differences doesn't appears unless I restart my WS.
Possibility
I believe it's about Hibernate caching but I didn't find anything that help me to fix it.
Does anybody already had this problem? Any idea?
hibernate.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<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/context_server</property>
<property name="hibernate.connection.username">user</property>
<property name="hibernate.connection.password"></property>
<mapping class="br.marcelo.bean.CsMediaAudio"/>
<mapping class="br.marcelo.bean.CsMediaImage"/>
<mapping class="br.marcelo.bean.CsMediaVideo"/>
<mapping class="br.marcelo.bean.CsContext"/>
<mapping class="br.marcelo.bean.CsMedia"/>
<mapping class="br.marcelo.bean.CsResource"/>
<mapping class="br.marcelo.bean.CsUser"/>
</session-factory>
</hibernate-configuration>
An service to Get informations:
#GET
#Path("/getResourceByIdXML/{id}")
#Produces(MediaType.APPLICATION_XML)
public CsResource getResourceByIdXML(#PathParam("id")Long id) {
return new DAOResource().find(id);
}
Class: DAOResource with find method used above:
public class DAOResource extends DAOGenerics<CsResource, Long> {
private final Session s;
public DAOResource()
{
s = HibernateSessionFactory.getSession();
}
#Override
public CsResource find(Long id) {
try {
s.flush();
s.clear();
String sql = "from CsResource where id = :id";
Query qr = s.createQuery(sql);
qr.setParameter("id", id);
return (CsResource) qr.uniqueResult();
}catch(HibernateException e){
System.out.println(e);
return null;
} finally {
s.close();
}
}
}
HibernateSessionFactory class with getSession method used above:
public class HibernateSessionFactory {
private static SessionFactory sf;
static
{
try
{
sf = new AnnotationConfiguration().configure("hibernate.cfg.xml").buildSessionFactory();
}
catch (Exception erro)
{
System.err.println(erro);
sf = null;
}
}
public static Session getSession()
{
return sf.openSession();
}
public static Connection getConnection(){
try {
SessionFactoryImplementor sessionFactoryImplementation = (SessionFactoryImplementor) sf;
ConnectionProvider connectionProvider = (ConnectionProvider)sessionFactoryImplementation.getConnectionProvider();
java.sql.Connection connection = connectionProvider.getConnection();
return connection;
} catch (SQLException ex) {
Logger.getLogger(HibernateSessionFactory.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
EDIT:
DAOGenerics class with call of flush() and clear() methods
public abstract class DAOGenerics<K, G> {
private final Session s;
public DAOGenerics()
{
s = HibernateSessionFactory.getSession();
}
public abstract K buscar(G obj);
public abstract List<K> buscarTodos();
public boolean inserir(K obj){
try {
s.flush();
s.clear();
s.getTransaction().begin();
s.saveOrUpdate(obj);
s.getTransaction().commit();
s.close();
return true;
}
catch (HibernateException erro){
System.out.println(erro.getMessage());
s.flush();
s.clear();
s.getTransaction().rollback();
s.close();
return false;
}
}
public void apagar(K obj) {
try {
apagar(obj, s);
} finally {
s.flush();
s.clear();
s.close();
}
}
public void apagar(K obj, Session s) {
try {
s.flush();
s.clear();
s.getTransaction().begin();
s.delete(obj);
s.getTransaction().commit();
}
catch (HibernateException erro){
System.out.println(erro);
s.flush();
s.clear();
s.getTransaction().rollback();
}finally{
s.close();
}
}
}
Yes, if you change something outside the "view" of hibernate, the hibernate caching does not realize that. So 2 options:
Use hibernate for your deletes/updates etc: This will take care that hibernate stays in sync and performance is the same as it is right now;
use clear or use stateless sessions: See org.hibernate.Session.clear() considered Harmful? for more details on that.
Related
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.
I'm using Hibernate 5.0.2.Final with a Data-Source connection (On a Tomcat 8.0.15) and started to ask myself if it's necessary to not only close the Session but also the SessionFactory?
Right now it looks like this:
public static List<HibernateList> getHibernateList() {
Session session = null;
final String hql = "SELECT H FROM myhibernate.MyHibernate";
try {
SessionFactory factory = HibernateUtil.getSessionFactory();
session = factory.openSession();
session.beginTransaction();
Query query = session.createQuery(hql);
return query.list();
} catch (HibernateException hibex) {
Logger.getLogger(Hibernatepicker.class.getName()).log(Level.INFO, null, hql);
Logger.getLogger(Hibernatepicker.class.getName()).log(Level.SEVERE, null, hibex);
} finally {
try {
if (session != null) {
session.close();
}
} catch (HibernateException hibex) {
}//Nothing I could do...
}
return null;
}
Some details from the hibernate.cfg.xml
<property name="hibernate.connection.datasource">java:comp/env/jdbc/sqlserv</property>
<property name="current_session_context_class">thread</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="hbm2ddl.auto">auto</property>
<property name="show_sql">false</property>
<property name="hibernate.generate_statistics">true</property>
And the HibernateUtil:
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
Configuration cfg = new Configuration();
sessionFactory = cfg.configure("hibernate.cfg.xml").buildSessionFactory();
} catch (Throwable ex) {
Logger.getLogger(HibernateUtil.class.getName()).log(Level.SEVERE, null, ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
I'm undecided whether it's necessary or not to call this method in the finally-block instead of only closing the session:
public static void disconnect(Session session, SessionFactory factory) {
try {
if (session != null) {
session.close();
} else {
Logger.getLogger(HibernateUtil.class.getName()).log(Level.INFO, null, "Session is Null");
}
} catch (HibernateException | NullPointerException hibex) {
Logger.getLogger(HibernateUtil.class.getName()).log(Level.INFO, null, "Couldn't close session, but there's nothing we can do...");
Logger.getLogger(HibernateUtil.class.getName()).log(Level.SEVERE, null, hibex);
}
try {
if (factory != null) {
factory.close();
} else {
Logger.getLogger(HibernateUtil.class.getName()).log(Level.INFO, null, "Factory is Null");
}
} catch (HibernateException | NullPointerException hibex) {
Logger.getLogger(HibernateUtil.class.getName()).log(Level.INFO, null, "Couldn't close session, but there's nothing we can do...");
Logger.getLogger(HibernateUtil.class.getName()).log(Level.SEVERE, null, hibex);
}
}
You should not close your SessionFactory on every query. Your SessionFactory should be initialised only once per application.
From the hibernate documentation.
The main contract here is the creation of Session instances. Usually
an application has a single SessionFactory instance and threads
servicing client requests obtain Session instances from this factory.
The internal state of a SessionFactory is immutable. Once it is
created this internal state is set. This internal state includes all
of the metadata about Object/Relational Mapping.
Implementors must be threadsafe.
I am having quite a bit of trouble with the testing of my dao.
I'll show the code at the end.
The problem is:
When i try to test different methods in dataDao: addData & updateData, I want to start over with a clean slot.
Has if when i call update after add i don't want the data added in the test for addData.
I do open a session in the setUp and close it in tearDown that are respecfully annoted with #Before and #After. The hibernate configuration is create-drop so that tables are new each time the session is closed and reopenned.
I am a bit new to hibernate but I did my research and looked it up on the internet for quite a time/weeks.
Here is what I am testing, the two classes: DataDAO and MyDaoManager (he is used because there are more then one table)
Thank you in advance for your help,
MyDaoManager.java
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
public abstract class MyDaoManager<T> {
private SessionFactory sessionFactory = null ;
/**
* <h2>Constructor which will get the sessionFactory from the class HibernateUtil</h2>
*/
public MyDaoManager(){
this.sessionFactory = HibernateUtil.getSessionFactory() ;
}
/**
* <h2>Method which gets the SessionFactory.</h2>
* #return A SessionFactory.
*/
public SessionFactory getSessionFactory() {
return sessionFactory;
}
/**
* <h2>Method which sets the SessionFactory at the moment of the construction.</h2>
* #param sessionFactory The SessionFactory to set.
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* <h2>Method which adds a given object from the model in the database.</h2>
* #param object Object to add.
*/
public boolean add(T object){
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
try {
session.save(object);
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
return true;
}
/**
* <h2>Method which updates a given Object from the model in the database.</h2>
* #param object Object to update.
*/
public void update(T object){
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
try {
session.merge(object);
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
}
/**
* <h2>Method which saves or updates a given Object from the model in the database.</h2>
* #param object Object to update.
*/
public void saveOrUpdate(T object){
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
try {
session.saveOrUpdate(object);
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
}
/**
* <h2>Method which gets an object from the model thanks to its id in the database.</h2>
* #param id The object's id to get.
* #return An object.
*/
public abstract T getOne(int id);
/**
* <h2>Method which gets all of an object from the model.</h2>
* #return A list of the object.
*/
public abstract List<T> getAll();
/**
* <h2>Method which deletes a given object thanks to its id.</h2>
* #param id The object's id to delete.
*/
public abstract void delete(int id);
}
Here is dataDao.java:
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class DataDao extends MyDaoManager<Data>{
#Override
public Data getOne(int id) {
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
Data data = null;
try {
Query query = session.createQuery("from Data d where d.id= :id").setParameter("id", id);
data = (Data)query.uniqueResult();
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
return data;
}
#SuppressWarnings("unchecked")
#Override
public List<Data> getAll() {
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
List<Data> list = null;
try {
list = session.createQuery("from Data d").list();
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
return list;
}
#Override
public void delete(int id) {
Session session = getSessionFactory().getCurrentSession();
Data data = getOne(id);
Transaction transaction = session.beginTransaction();
try {
session.delete(data);
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
}
}
Here is my test, DataDaoTest.java:
import static org.junit.Assert.assertTrue;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.hibernate.Session;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class DataDaoTest{
private Session session;
private DataDao dataDao;
#Before
public void setUp(){
session = HibernateUtil.getSessionFactory().openSession();
dataDao = new DataDao();
dataDao.setSessionFactory(session.getSessionFactory());
}
#After
public void tearDown(){
session.close();
}
#Test
public void addDataTestShouldWork(){
Data dataTest = new Data();
dataTest.setDate(new Date(System.currentTimeMillis()));
dataTest.setSensor(new Sensor());
dataTest.setValue("test");
dataTest.setIsOnPhone(true);
assertTrue("No add",dataDao.add(dataTest));
List<Data> founded = dataDao.getAll();
DataEqualsBuilder dataEqualsBuilder = new DataEqualsBuilder(dataTest);
assertTrue("Not the same object added and founded", dataEqualsBuilder.equals(founded.get(0)));
}
#Test(expected=RuntimeException.class)
public void addDataTestShouldNotWork(){
dataDao.add(null);
}
#Test
public void updateDataTestShouldWork(){
Data dataTest = new Data();
dataDao.add(dataTest);
dataTest.setValue("test1");
dataDao.update(dataTest);
List<Data> founded = dataDao.getAll();
DataEqualsBuilder dataEqualsBuilder = new DataEqualsBuilder(dataTest);
assertTrue("Not the same object added and founded", dataEqualsBuilder.equals(founded.get(0)));
}
public class DataEqualsBuilder extends EqualsBuilder {
private Data data;
public DataEqualsBuilder( Data data){ this.data= data; }
#Override
public boolean equals(Object obj) {
if (obj == null) { return false; }
if (obj == this) { return true; }
if (obj.getClass() != data.getClass()) {
return false;
}
Data rhs = (Data) obj;
return (DataEqualsBuilder.reflectionEquals(data, rhs, "sensor"));
}
}
}
Finally my hibernate configuration:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/APISensor</property>
<!-- TODO create specific user -->
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">false</property>
<property name="hbm2ddl.auto">create-drop</property>
</session-factory>
</hibernate-configuration>
Try removing this Hibernate property:
<property name="current_session_context_class">thread</property>
And change your setup/tearDown to:
#Before
public void setUp(){
session = HibernateUtil.getSessionFactory().openSession();
ThreadLocalSessionContext.bind(session);
dataDao = new DataDao();
dataDao.setSessionFactory(session.getSessionFactory());
}
#After
public void tearDown(){
session.close();
ThreadLocalSessionContext.unbind(sessionFactory);
}
In our web application we have a HibernateSessionFactory class, that is opening and closing connections. Everything is okay, but when we are updating data in the database, it doesn't change in our application. Unfortunately, we see old data from the database. How can I fix it?
public class HibernateSessionFactory {
private static final ThreadLocal threadLocal = new ThreadLocal();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
private static ServiceRegistry serviceRegistry;
private static final Logger log = Logger.getLogger(HibernateSessionFactory.class);
static {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())
. buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
log.error("Error Creating SessionFactory",e);
}
}
private HibernateSessionFactory() {
}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory() {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder(). applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
log.error("Error Creating SessionFactory",e);
}
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.flush();
session.close();
}
}
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Configuration getConfiguration() {
return configuration;
}
}
Hibernate is a sofisticated and complex framework for building a layer between your program and the database, providing an object oriented model to help object oriented programs in their job.
In order to do this, and to be more performat of course, it creates a cache which stores somehow some of the data coming from the database, or going to the database.
I think that this problem is NOT concerning the connection to the database but rather how you save and retrive data.
I'll try to explain my self better: when you query database to save data you do the following steps:
open session
open transaction
build object
flush and save object in session
commit transaction
close transaction
close session
eg
public Boolean saveNewCliente(Cliente c) {
Session s = getSession();
Transaction t = null;
try {
t = s.beginTransaction();
s.save(c);
s.flush();
t.commit();
s.close();
return true;
} catch (Exception e) {
if (t!=null) t.rollback();
System.out.println(e.getMessage());
return false;
}
finally{
s.close();
}
}
A common pitfall happens when you query database to fetch data, is to leave the part relating the transaction out of your "query" steps. As well for saving data you have to
open session
open transaction
build query / criteria
execute query over session
close transaction
close session
If you don't follow this steps is possible that you have stale data in your application, but not in your database. A check may be to execute your update/save-query and check manually in the database if the data has changed/created. If your application then loads stale data you know you do the fetch-query in the wrong way(without using transaction).
Here's a snipped of example
public Cliente get(Integer id) {
Session s = getSession();
Transaction tx = s.beginTransaction();
try {
System.out.println("get cliente by id");
Cliente res = new Cliente();
res = (Cliente) s.get(Cliente.class, id);
tx.commit();
return res;
} catch (Exception e) {
tx.rollback();
System.out.println(e.getMessage());
return null;
}finally{
s.close();
}
}
If you want to furthermore investigate you can suspend the usage of cache by hibernate, you can do it in the following way, but remember that if data is cached there is a reason ;)
This can be useful as a quick test in order to proceed in discovering if the error is due to wrong query usage.
You should add this to your hibernate config xml
<!-- to disable cache -->
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.use_query_cache">false</property>
I'm working on Struts 2 Framework with Hibernate 3.3 and using Oracle 11g. My web project was working fine since 5 months. But recently I'm facing the java.sql.SQLRecoverableException: Closed Connection during some idle time. I'll explain the scenario follows..
My hibernate.cfg.xml configuration is
<property name="hibernate.current_session_context_class">
thread
</propert
<property name="connection.url">jdbc:oracle:thin:#localhost:1521:orcl</property>
<property name="connection.username">user</property>
<property name="connection.password">user</property>
<property name="connection.driver_class">
oracle.jdbc.OracleDriver
</property>
<property name="myeclipse.connection.profile">Oracle</property>
<property name="hibernate.connection.autoReconnect">true</property>
<property name="dialect"> org.hibernate.dialect.Oracle10gDialect </property>
And my HibernateSessionFactory conf is
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static Configuration configuration = new Configuration();
private static org.hibernate.SessionFactory sessionFactory;
private static String configFile = CONFIG_FILE_LOCATION;
static {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println("%%%% Error Creating SessionFactory %%%%");
//e.printStackTrace();
}
}
private HibernateSessionFactory() {
}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory() {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println("%%%% Error Creating SessionFactory %%%%");
//e.printStackTrace();
}
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void setConfigFile(String configFile) {
HibernateSessionFactory.configFile = configFile;
sessionFactory = null;
}
public static Configuration getConfiguration() {
return configuration;
}
Then the error comes when the following code runs
session = HibernateSessionFactory.getSession();
Query query = session.createQuery(SQL_QUERY);
try {
// session.connection().close();
System.out.println("CLOSED :"
+ session.connection().isClosed());
if (session.connection().isClosed()) {
System.out.println("RECONNECTING.......");
session.reconnect();
}
System.out.println("CLOSED :"
+ session.connection().isClosed());
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
for (Iterator it = query.iterate(); it.hasNext();) {
chk = true;
ur = (EmagEnterpriseLogin) it.next();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
When the above snippet runs even though able to session was opened and created query successfully, But fails at Iterating query. First time comes as
Caused By:java.sql.SQLRecoverableException: Closed Connection
But before this error in first try i captured the session.Connection.isClosed() was false. But after first error then keeps on coming as SQL State=null and from second time i could get session.Connection.isClosed() was true. And then reconnecting executes but still the same error repeats.I also tried rebuilding sessionfactory, that too failed. Please help me to solve this issue.
Finally i found the solution for my problem is using third party Connection Provider instead of using Hibernate Native connection provider. I used c3p0 Connection provider , that also given me some problems and i solved that too. The reference link for c3p0 is here.. Hibernate c3p0 Connection NewPooledConnection close Exception