11.3.2. Extended session and automatic versioning
A single Session
instance and its persistent instances are used for the whole conversation, known as
session-per-conversation
. Hibernate checks instance versions at flush time, throwing an exception if concurrent modification is detected. It's up to the developer to catch and handle this exception (common options are the opportunity for the user to merge changes or to restart the business conversation with non-stale data).
The Session
is disconnected from any underlying JDBC connection when waiting for user interaction. This approach is the most efficient in terms of database access. The application need not concern itself with version checking or with reattaching detached instances, nor does it have to reload instances in every database transaction.
// foo is an instance loaded earlier by the old session
Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
foo.setProperty("bar");
session.flush(); // Only for last transaction in conversation
t.commit(); // Also return JDBC connection
session.close(); // Only for last transaction in conversation
The foo
object still knows which Session
it was loaded in. Beginning a new database transaction on an old session obtains a new connection and resumes the session. Committing a database transaction disconnects a session from the JDBC connection and returns the connection to the pool. After reconnection, to force a version check on data you aren't updating, you may call Session.lock()
with LockMode.READ
on any objects that might have been updated by another transaction. You don't need to lock any data that you
are
updating. Usually you would set FlushMode.NEVER
on an extended Session
, so that only the last database transaction cycle is allowed to actually persist all modifications made in this conversation. Hence, only this last database transaction would include the flush()
operation, and then also close()
the session to end the conversation.
This pattern is problematic if the Session
is too big to be stored during user think time, e.g. an HttpSession
should be kept as small as possible. As the Session
is also the (mandatory) first-level cache and contains all loaded objects, we can probably use this strategy only for a few request/response cycles. You should use a Session
only for a single conversation, as it will soon also have stale data.
(Note that earlier Hibernate versions required explicit disconnection and reconnection of a Session
. These methods are deprecated, as beginning and ending a transaction has the same effect.)
Also note that you should keep the disconnected Session
close to the persistence layer. In other words, use an EJB stateful session bean to hold the Session
in a three-tier environment, and don't transfer it to the web layer (or even serialize it to a separate tier) to store it in the HttpSession
.
The extended session pattern, or
session-per-conversation
, is more difficult to implement with automatic current session context management. You need to supply your own implementation of the CurrentSessionContext
for this, see the Hibernate Wiki for examples.