I usually use the Hibernate ThreadLocal session management pattern in Java web projects:
The Thread Local Session pattern makes use of the java.lang.ThreadLocal class to create a Session that is accessible from a single application thread. This is particularly convenient in multithreaded applications, such as web applications.
In projects I implement this with
<property name="current_session_context_class">thread</property>
in the hibernate.xml
and using SessionFactory.getCurrentSession()
to get a session whenever I need one.
Now I have a program that is not a Servlet, but does heavy parallel computing and database interaction.
I want to implement this with a ForkJoinPool. Now I wonder whether it is a mistake to use Hibernate ThreadLocal session management in this scenario. As far as I understand, a ForkJoinPool uses a smaller number of threads and shares them among running tasks while other tasks are sleeping. (Motivated by stalling/annoying " task in transaction' connections,) I want to close() every Hibernate Session after a unit of work.
So.. when I call HibernateSessionFactory.getThreadLocalSession().close() at the end of my Task - and the Task is run in a ForkJoinPool - will troubles arise? Should I drop the ThreadLocal pattern for heavy parallel calculations and manage the Sessions myself?
Thanks in advance for any answers.
If you were sharing a Hibernate Session between two threads, then one thread changes might not be visible to some other thread (without proper synchronization or volatile reads).
The SessionFactory is a thread safe object and used by all the threads of an application. The SessionFactory is a heavyweight object; it is usually created during application start up and kept for later use. You would need one SessionFactory object per database using a separate configuration file.
A Session is used to get a physical connection with a database. The Session object is lightweight and designed to be instantiated each time an interaction is needed with the database. Persistent objects are saved and retrieved through a Session object.
The Session interface is the main tool used to communicate with Hibernate. It provides an API enabling us to create, read, update, and delete persistent objects. The session has a simple lifecycle. We open it, perform some operations, and then close it.
Using ThreadLocalSessionContext
could be problematic for you, but it depends on what your tasks are doing.
A ForkJoinPool
(javadocs) is meant for use in cases where tasks spawn other tasks (the fork), and wait for them to complete (the join). While waiting, the Thread that was executing the parent task may be re-used to execute a child task. According to the javadocs for ThreadLocalSessionContext, the Session
gets closed when you commit a transaction you get from it (ie there's only ever one transaction per Session
).
So, if you have a 'parent' task that calls sessionFactory.getCurrentSession()
, and does some stuff, then calls commit(), the Session gets closed and there's no danger of inappropriate interaction.
However, if you spawn children tasks AFTER calling .getCurrentSession()
and BEFORE calling .commit()
, you may run in to issues because other tasks may execute on this Thread, and .getCurrentSession()
would return the session used by the parent task. This is almost certainly not what you want, because the children tasks should presumably be doing the same thing as each other, and you wouldn't want one arbitrarily sharing Session
state with the parent while others don't.
So in summary, you should:
session.close()
if you get the Session
from .getCurrentSession()
, because it's the responsibility of the CurrentSessionContext
to deal with that..commit()
before spawning children tasks.As a footnote, I found this wiki page to be a helpful read on the subject as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With