Is Hibernate's session thread safe? - java

I need to know, whether the Hibernate's session is thread safe or not. But obvious a new session is attached to every thread for execution. But my question is if in one thread I have updated some value of an entity, so will that be reflected in other thread during same time execution?
My problem is when I fire update from two threads sequentially, the value is updated properly but when I fire the update almost altogether then it fails.
for eg.
current stage of table.
ID NAME MARKS
------- --------- --------
1 John 54
I am trying to do follwing :
Student student = session.load(Student.class, 1);
student.setMarks(student.getMarks() + 1);
session.update(student);
session.close();
When I try to run the above code in loop say 10, then value of "marks" in table "student" is properly updated i.e. the value gets updated to 64 which is proper.
But when I try to run the same code in threaded environment, it gives bad results.

It is not intended that implementors be threadsafe. Instead each thread/transaction should obtain its own instance from a SessionFactory.
Even with this in mind, your behaviour might still not be what you expect, because transactions come into play. You will have to set a proper transaction isolation level. See the configuration guide, hibernate.connection.isolation property.

Hibernate session and threads do not mix.
You should not use a session from multiple threads at once, and I recommend you only use a session from a single thread. DB session implementations are not even required to be theadsafe.
You also must consider what happens to the transactions when you start doing things in multiple threads. Transactions are tied to the current thread. This becomes quickly mindblowing and you enter areas where the implementers have not tested their products.
In the end life is too short to get lost in that swamp.

It depends on how you are creating a session.
Session can be created in two ways in hibernate.
getCurrentSession()
Yes. It offers thread safety as it'll ensure that it'll create a session for each thread if session not exist. transaction and automatic session closing is attached to this.
openSession()
It's not thread safe. developer manually needs to manage transactions and session flush and close operations.

Hibernate sessions are not thread safe. Use TheadLocal class to create sessions for each thread:-
private static ThreadLocal<Session> threadSafeSession = new ThreadLocal<Session>() {
protected Session initialValue(){
return sf.openSession();
}
};
In your method get session for each thread as:-
Session session = threadSafeSession.get();

Related

How many transactions do we get when two threads visit a method with #Transactional at the same time?

Let's say that we have this code:
#Transactional
public String getUser(long id) {
User user = userDao.getUserById(id);
if(user == null) {
user = new User();
user.setXXX(XXX);
userDao.insert(user);
}
}
Assuming that datasource is mysql5:
How many transactions do we get if two threads visit getUser() method at the same time? If the answer is two, then what is the relationship between the two transactions?
As of Spring Documentation:
The getTransaction(..) method returns a TransactionStatus object,
depending on a TransactionDefinition parameter. The returned
TransactionStatus might represent a new transaction, or can represent
an existing transaction if a matching transaction exists in the
current call stack. The implication in this latter case is that, as
with Java EE transaction contexts, a TransactionStatus is associated
with a thread of execution.
Which means that for every thread Spring will create a new transaction, unless there is already one existing for that thread.
When two threads enter this method, two separate transactions are created and there is no relation between them. There is no nesting or anything going here (that is a different scenario). The only case that i can think of where there would be any relation is when the Propagation.REQUIRES_NEW is used, but this is not the case here.
How many transactions do we get if two threads visit getUser() method at the same time?
The answer to this depends on the connection factory and the database type. If you are using a connection pool or otherwise creating two connections then each thread will get a separate transaction with the database. The details here are highly dependent on your connection pool and database settings.
If the answer is two, so what is the relationship between the two transactions?
This depends on what the database does with these transactions. It is important to realize that transactions are not about mutex but are rather about database coherency. To quote from wikipedia:
A transaction symbolizes a unit of work performed within a database management system (or similar system) against a database, and treated in a coherent and reliable way independent of other transactions. A transaction generally represents any change in database.
How the transactions interact depends highly on what type of transaction is created and what is being done inside them. If you are asking if it is possible for 2 threads to lookup a User with the same id at the same time and then try and create the same User twice then the answer is definitively yes.
One problem with this is that both userDao.insert(...) calls might succeed but the 2nd one to commit its transaction (race condition alert) might throw some sort of unique constraint exception but that might at a AOP level and not in your code.

Impact of opening a hibernate session and not closing it

I lately observed a problem in my code, I opened a hibernate session but forgot to close it. Although I fixed it but I can't seem to understand the impact of this mistake I did.
This code was in HTTP service, I need answers for two cases:
The container spawns a new thread when a request comes
It fetches from thread pool
I have read in other posts that session is bound to thread, so what I have inferred from that is if a new thread is spawned in each request and I have left a session open in one of them. It will be then destroyed when request gets completed. I dont know I am right or not.
It depends of what you use to control a session life cycle.
If you use a "session per request pattern" with, for an example, OpenSessionInViewFilter, a session will be closed by a filter. You can use your own filter to control a session as well.
If you don't use filters or similar stuff you should always close a session.
Threads that process requests know nothing about Hibernate session.
SessionFactory.openSession() always open a new session.
SessionFactory.getCurrentSession() do a check, if the current session exists β€” return it, if the current session doesn't exist β€” create a new one. A meaning of "current session" depends of a session factory parameters. In the classical case, a session is bounded to the thread (as you describe), but it can be bounded to the transaction, for an example.

Logical Unit of Work and Single Unit of work in JPA, JTA

I often came across these terms. Is their a difference b/w the 2 of them?
In the following piece of Java code, the method is thread-safe:
class Counter {
private int i = 0;
public synchronized void inc() {
i++;
}
}
In context to SessionFactory and Session in Hibernate then,
SessionFactory (org.hibernate.SessionFactory) - A thread-safe
Session (org.hibernate.Session) - A single-threaded, short-lived object representing a
conversation between the application and the persistent store.
I get confused here in understanding their definition.
All i absorb is that since SessionFactory is thread-safe, any thread first needs to acquire a lock and then would be working on it, i.e Implementation is guaranteed to be free of race conditions when accessed by multiple threads simultaneously. (Notice i wrote simultaneously and not parellely). After one thread has finished its work, another one in queue would be acquiring the lock then and so on. No 2 threads will be working on it exactly at the same time.
Session is not thread safe, and it represents a single-threaded unit of work.
Is it that after a sessionfactory, multiple sessions (in a sessionfactory) will be evolving each span their own work in their own single-thread?
A SessionFactory is thread-safe and you have a singleton Sessionfactory for a given DataSource.
The Sessions can either be created for the life time of a single request or even extended to span over multiple user requests.
The Session has always have to be bound to a single Thread at any given time. Even when you use an extended persistence context, it's only one request/thread to access the Session at a point-in-time.
So the Session should not be accessed concurrently. That's why you don't need to synchronize your entities, at least not from Hibernate point of view. Each Session loads it's own copy of an entity and the concurrency is usually ensured with optimistic locking because it's desirable to have application-level repeatable reads.
So entities should not be synchronized. The concurrency control happens inside the database, not in your application logic. Each client request will always issue DML statements in the scope of a physical database transaction, and database transactions always acquire locks when rows get changes (even for READ_COMMITTED).
All in all, the Session is not tread-safe along with all its attached Entities. The Session factory is thread-safe because you get only one singleton instance per DataSource and you use it to create new Sessions.

Multiple transactions in a single hibernate session (with Spring)

Is it possible to model the following using Hibernate + Spring.
Open session
Begin transaction
Do some work
Commit
Begin transaction
More work
Commit
Close session
I use the Spring TransactionTemplate which does both session + transaction lifetime scoping.
The reason is that sometimes I have a few stages in a business process and I would like to commit after each stage completes. However I would like to continue using the same persistent objects. If I have a separate session per transaction then I get transient/detached exceptions because the original session was closed.
Is this possible?
Yes, Hibernate's Sessions can begin and commit several transactions. What you need to do is to store open session somewhere, then reuse it. Note, that Session is not a thread-safe object, but if you're sure it won't have problems with concurrency, what you need is just to use TransactionSynchronizationUtils to bind a session to the thread resources and then unbind it when desired, you can find an example here or you can take a look at OSIV and its standard implementations.
This is a very complicated thing, it's much easier and thus desirable that you close your session right away and don't reuse it, because it may bring troubles:
The objects inside of cache are not automatically evicted, thus your Session will grow in size until OutOfMemory.
The objects inside of session are not flushed unless they are dirty, thus the chance that object was changed by another user is larger and larger. Ensure that only a single user is going to change writable objects.
If some exception happens during one of steps, you have to ensure you close the session. After exception occurred inside of Session, this object is not reusable.
If transaction was rolled back, the session is cleared by Spring, thus all your objects become detached. Make sure your discard everything if at least one of transactions was rolled back.
You could achieve this using the OpenSessionInView pattern. Spring provides a javax.servlet.Filter implementation which you could use if you're working in a servlet environment (question doesn't say so). This will ensure that your Hibernate session is kept open for the duration of the request rather than just for an individual transaction.
The Javadoc on this class is pretty comprehensive and might be a good starting point.

getCurrentSession hibernate in web

I am writing a web based application with hibernate and jsp/servlet. I have read about the sessionFactory.getCurrentSession and sessionFactory.openSession methods. I know the basic difference between them (using getCurrentSession you don't have to close the connection and when you commit the transaction, your session will automatically close). According to the my understanding, we should opt for getCurrentSession and do it through session-per-request.
Let's consider the following scenario:
Method A calls getCurrentSession and got the current session
In Method A, a transaction is started using the session from step 1
Method A calls Method B, which also has getCurrentSession and starts a transaction
Method B commits its transaction
Control returns to method A and it also commits the transaction
Now my questions are
Will the session found in step 1 and step 3 will be the same session?
If the answer for the question 1 is yes, then how would it handle the commit in step 4? Ideally it should close the session there itself and should throw an exception at step 5.
If the answer for the question 1 is no, then how do you handle such a scenario?
Will the session found in step 1 and step 3 will be the same session?
They should be the same, that's somehow part of the contract of getCurrentSession() and you'll get the Session bound to the thread as long as the unit of work has not been completed (i.e. a transaction has been committed or rolled back). Java Persistence with Hibernate puts it like this (p.481):
All the data-access code that calls getCurrentSession() on the global shared
SessionFactory gets access to the same current Session β€” if it’s called in the
same thread. The unit of work completes when the Transaction is committed (or rolled back). Hibernate also flushes and closes the current Session and its persistence context if you commit or roll back the transaction. The implication here is that a call to getCurrentSession() after commit or rollback produces a new Session and a fresh persistence context.
And you might also want to read what the javadoc of Session#beginTransaction() says.
If the answer for the question 1 is yes, then how would it handle the commit in step 4. Ideally it should close the session there itself and should give error at step 5.
Step 4 shouldn't be a problem, the Session will be flushed, the Transaction will be committed and the Session closed. But I expect step 5 to fail wih aTransactionException (that's my bet). But let me quote the javadoc of Transaction:
A transaction is associated with a Session and is usually instantiated by a call to Session.beginTransaction(). A single session might span multiple transactions since the notion of a session (a conversation between the application and the datastore) is of coarser granularity than the notion of a transaction. However, it is intended that there be at most one uncommitted Transaction associated with a particular Session at any time.
As underlined above, we are discussing around something that shouldn't happen (i.e. a design problem).
I don't have an answer for your scenario because I would not implement it that way as it seems to be asking for trouble. Instead, I'd start the transaction in C, where C invokes A and B, and have C issue the commit. Skeletally:
public void c(...) {
try {
transaction.begin();
a();
b();
transaction.commit();
catch (Exception e) {
transaction.rollback();
}
}
So here, a() and b() do not commit or rollback - how do they know the entire business task has been completed? They could throw an exception or perhaps return a boolean to tell the caller that something is amiss and a rollback is needed.

Categories