In my application i have a situation where i need to do a recursive call to a method to achieve requirement.
But when i call the method I am getting
_Exception in thread "main" org.hibernate.SessionException: Session was already closed
at org.hibernate.internal.SessionImpl.close(SessionImpl.java:410)
at com.cerner.core.dao.oracleImpl.test.TestRecurssionSessionClose.fact(TestRecurssionSessionClose.java:40)
at com.cerner.core.dao.oracleImpl.test.TestRecurssionSessionClose.main(TestRecurssionSessionClose.java:49)
_
I have test code for this
public class TestRecurssionSessionClose {
private SessionFactory factory;
private Session session;
private Transaction transaction;
public TestRecurssionSessionClose() {
HibernateUtil.configureSessionFactory();
factory = HibernateUtil.getFactory();
}
public int fact(int n) {
System.out.println(factory.isClosed());
session = factory.openSession();
transaction = session.beginTransaction();
try {
if (n == 1) {
return 1;
} else {
System.out.println(n);
return (n * fact(n - 1));
}
} catch (
HibernateException ex) {
if (transaction != null)
transaction.rollback();
return 0;
} finally {
if (session != null) {
session.close();
}
}
}
public static void main(String[] args) {
TestRecurssionSessionClose testRecurssionSessionClose = new TestRecurssionSessionClose();
System.out.println(testRecurssionSessionClose.fact(3));
}
}
I am new to hibernate. please tell me what I am missing here?
By default some hibernate versiones have hibernate.transaction.auto_close_session to true. This makes that the session is closed automatically without requirement to close.
Disable the auto close session or better use automatic session context management
See: Session configuration
Related
I am trying to do a simple saveOrUpdate operation using a Transaction Manager in Hibernate but, the context is not flushed to the DB tables. I suspect, the Transaction Manager is not able to resolve the end of the transaction and hence, doesn't flush the changes.
The changes are reflected in the DB Table if a session.flush() is done explicitly. I am using the Default flush mode, which is AUTO.
There are a couple of other questions on SO that talk about the same, but none of them have helped in my case.
#Transactional(transactionManager="txManager", readOnly=false)
public Integer setNamesTable(Names names) {
session = getSession();
Integer id = null;
if (session != null) {
try {
id = (Integer) session.save(names);
} catch (Exception ex) {
System.out.println(ex);
}
LOGGER.info("Exiting setNmlAggrTcaPhn");
}
return id;
}
Have Autowired SessionFactory as below,
#Autowired
#Qualifier("hibernateTestAnnotatedSessionFactory")
SessionFactory sfc;
private synchronized Session getSession() {
try {
session = sf.getCurrentSession();
if (session != null) {
return session;
} else {
session = sf.openSession();
}
} catch (HibernateException ex) {
session = sf.openSession();
}
return session;
}
This is the command to display information data sheet, I see the declaration it is repeated
CODE 1
public class DBTable {
public List<MdGmail> showGmail() {
Configuration conf = new Configuration().configure("hibernate.cfg.xml");
SessionFactory sf = conf.buildSessionFactory();
currentSession = sf.getCurrentSession();
currentSession.beginTransaction();
return currentSession.createCriteria(MdGmail.class).list();
}
public List<MdBlogger> showBlogger() {
Configuration conf = new Configuration().configure("hibernate.cfg.xml");
SessionFactory sf = conf.buildSessionFactory();
currentSession = sf.getCurrentSession();
currentSession.beginTransaction();
return currentSession.createCriteria(MdBlogger.class).list();
}
}
In my class DBTable,I create a list function to display data table in a database as table gmail,order...
With the first code 1 need to rewrite the declaration for each function, so what I want is to create a connection function for all with code 2
But with the way this declaration it will not update the value was changed in the database
CODE 2
public class DBTable {
private static final Configuration conf = new Configuration().configure("hibernate.cfg.xml");
private static final SessionFactory sf = conf.buildSessionFactory();
private static Session currentSession;
public DBTable() {
currentSession = sf.getCurrentSession();
currentSession.beginTransaction();
}
private static DBTable instance = null;
public static DBTable getInstance() {
if (instance == null) {
instance = new DBTable();
}
return instance;
}
public List<MdGmail> showTableGmail() {
return currentSession.createCriteria(MdGmail.class).list();
}
public List<MdGmail> showTableOrder() {
return currentSession.createCriteria(MdGmail.class).list();
}
}
And if use new additional data function, the connection will be closed and command data showing that my table would stop working.Please help me
public boolean saveOrUpdateGmail(MdGmail table) {
try {
currentSession.saveOrUpdate(table);
currentSession.getTransaction().commit();
return true;
} catch (Exception e) {
currentSession.getTransaction().rollback();
e.printStackTrace();
return false;
}
}
The simplest strategy of using Hibernate is open a session (or get current one), begin a transaction, do request, commit, and close a session for every operation (showTableGmail, saveOrUpdateGmail). So you need to delete all code from DBTable() constructor and do something like this.
Sorry for my english. I learn JavaEE and i dont know proper or not i use session in hibernate. How to use them? I use pattern DAO and hibernate. Tell my how property use session
this is HibernateUtil class
private static final SessionFactory sessionFactory;
static {
try{
sessionFactory = new Configuration().configure("/app/web/landingpage/HibernateConnect/hibernate.cfg.xml").buildSessionFactory();
}catch(Throwable ex) {
System.out.println("Error " + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void close(Session session) {
if (session != null) {
try {
session.close();
} catch (HibernateException ignored) {
System.out.print("Couldn't close Session" + ignored);
}
}
}
And that class makes all operation db CategoryDaoImpl
public class CategoryDaoImpl implements CategoryDao{
private Session session = null;
//get all category
public Collection getAllCategory() {
List categoris = new ArrayList<Category>();
try{
session = HibernateUtil.getSessionFactory().openSession();
categoris = session.createCriteria(Category.class).list();
}catch(Exception e) {
System.out.println("getAllCategory "+ e);
}finally{
if(session != null && session.isOpen())
session.close();
}
return categoris;
}
//get category id
public Category getCategory(int id) {
Category cat = null;
try {
session = HibernateUtil.getSessionFactory().openSession();
cat = (Category) session.load(Category.class, id);
}catch(Exception e) {
System.out.println("getAllCategory "+ e);
}finally{
if(session != null && session.isOpen())
session.close();
}
return cat;
}
//and below few methods that use it the some way session
}
and this servlet take results indexuser
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
try{
Collection allcategory = Factory.getInstance().getCatDAO().getAllCategory();
request.setAttribute("allcategory", allcategory);
request.getRequestDispatcher("/index.jsp").forward(request, response);
} catch(Exception e) {
System.out.println(e);
} finally{
if(session!=null && session.isOpen())
session.close();
}
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.
Basically session is used to get physical connection with database. So while you performing any DB Operations it will first open Session using sessionFactory and then Session do physical connection with database and then perform your operation and after performing operation you can close it.
Session is light weight.
I'm hunting down a memory leak in a JSF application. I've read various articles that discuss potential memory leaks when using threads with transactions and sessions. Does the following code seem like it could produce a leak? This code is called thousands of times (for page requests).
public class HibernateHelper
{
private static final ThreadLocal threadSession = new ThreadLocal();
private static final ThreadLocal threadTransaction = new ThreadLocal();
public static Session startSessionWithDBName(SessionFactorySingleton.DBname dbname)
{
Session s = getSessionWithDBName(dbname);
beginTransaction(dbname);
return s;
}
#SuppressWarnings("unchecked")
private static Session getSessionWithDBName(SessionFactorySingleton.DBname dbname)
{
Session s = (Session) threadSession.get();
if (s == null)
{
s = SessionFactorySingleton.getSessionFactory(dbname).openSession();
threadSession.set(s);
}
else
{
String sf = ((SessionFactoryImpl)s.getSessionFactory()).getProperties().getProperty("hibernate.session_factory_name");
if((dbname !=null && sf !=null) && !sf.equals(dbname.toString()))
{
closeSessionBySessionFactoryName(sf);
s = SessionFactorySingleton.getSessionFactory(dbname).openSession();
threadSession.set(s);
}
}
return s;
}
#SuppressWarnings("unchecked")
public static boolean isSessionOpen()
{
Session s = (Session) threadSession.get();
if (s != null)
return s.isOpen();
return false;
}
public static boolean wasTransactionCommited()
{
Transaction t = (Transaction) threadTransaction.get();
if (t != null)
return t.wasCommitted();
return false;
}
#SuppressWarnings("unchecked")
public static void closeSessionBySessionFactoryName(String sessionfactoryname) {
Session s = (Session) threadSession.get();
if (s != null && s.isOpen())
{
String sfname = ((SessionFactoryImpl)s.getSessionFactory()).getProperties().getProperty("hibernate.session_factory_name");
if(sfname.equals(sessionfactoryname))
{
try
{
commitTransaction(sfname);
} catch (Exception e) {
e.printStackTrace();
}
s.close();
threadSession.set(null);
}
}
}
/**
* Start a new database transaction.
*/
private static void beginTransaction(SessionFactorySingleton.DBname dbname) {
Session s = (Session) threadSession.get();
if(s!=null)
{
log.info("Starting new transaction for this thread.");
Transaction tx = s.beginTransaction();
threadTransaction.set(tx);
}
}
/**
* Commit the database transaction.
*/
public static void commitTransaction(String sessionfactoryname) throws Exception {
Transaction tx = (Transaction) threadTransaction.get();
try {
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.commit();
log.info("Committed transaction for thread "+ Thread.currentThread().getName());
}
threadTransaction.set(null);
} catch (Exception e)
{
log.error("Exception when committing transaction: ", e);
rollbackTransactionKeepingSessionOpen();
throw e;
}
}
/**
* Rollback the database transaction.
*/
public static void rollbackTransactionKeepingSessionOpen() {
Transaction tx = (Transaction) threadTransaction.get();
threadTransaction.set(null);
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.rollback();
}
}
}
Yes it does.
Each threadLocal instance is bound to a lifespan of a thread that uses it.
Tomcat's thread pool can easily have hundreds of threads; each thread is reused and never destroyed.
Some of them will be stuck in an I/O operation, querying DB or whatnot, at the same time holding a reference to an open Hibernate session (which in turn may contain a lot of attached entities).
So during some periods the application may have many big object graphs that cannot be reclaimed by GC.
I think you should manage Hibernate sessions and transactions in a different way.
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>