Spring @Transactional Declarative Transaction Management Getcurrentsession
in spring @Transactional the configuration of declarative transaction management, Hibernate.current_session_context_class=thread ...
This sentence cannot be added ... If you add it, it will go wrong. Then why not add it?
that's because in spring transaction management, the current session is bound to Springsessioncontext in the Threadlocalsessioncontext, not in the
First, combine bernate4.0 to say:
From the beginning, the background implementation of sessionfactory.getcurrentsession () is pluggable. As a result, we have introduced new extension interfaces (Org.hibernate.context.spi.CurrentSessionContext) and
The new configuration parameter (Hibernate.current_session_context_class) to unplug the definition of what is the scope and context (scope and context) for the current session.
It defines a single method, Currentsession (), which is used by the specific implementation to track the current context session.
first, let's see Org.hibernate.context.spi.CurrentSessionContext .
There is only one method for this interface:
Sessioncurrentsession()
Throws Hibernateexception
Retrieve thecurrent Session According to the scoping defined by this implementation.
currentsession () indicates that the current session is returned based on the implementation and definition of the current Currentsessioncontext
This interface ... There are 3 classes in hibernate that implement this interface
All known implementing Classes:
Jtasessioncontext, Managedsessioncontext, Threadlocalsessioncontext
1:org.hibernate.context.internal.threadlocalsessioncontext -The current session is tracked and defined through the currently executing threads.
2:org.hibernate.context.internal.jtasessioncontext-current session According to JTA to track and define. This is exactly the same as the previous method of supporting JTA only.
3:org.hibernate.context.internal.managedsessioncontext.
Spring also implements this interface for transaction management:
1:org.springframework.orm.hibernate4.springsessioncontext– The current session is tracked and defined according to the spring and transaction manager.
These implementations provide a programming model for "one session per database transaction", also called a session per request. The start and end of Hibernate session is controlled by the existence of database transactions.
The Hibernate.current_session_context_class configuration parameter defines which Org.hibernate.context.spi.CurrentSessionContext implementation should be used.
Generally, the value of this parameter indicates the full name of the implementation class to be used, but the two built-in implementations can use shorthand, "JTA" and "thread".
Hibernate.current_session_context_class=thread
The essence is:
hibernate.current_session_context_class= Org.hibernate.context.internal.ThreadLocalSessionContext
similarly:
Hibernate.current_session_context_class=jta
The essence is:
hibernate.current_session_context_class= Org.hibernate.context.internal.JTASessionContext
In Spring @Transactional Declarative Transaction management, the definition of "currentsession" is: The session currently managed by the Spring transaction manager, which should be configured at this time:
hibernate.current_session_context_class=Org.springframework.orm.hibernate4.SpringSessionContext
After spring consolidates hibernate management transactions, the currentsession is bound to springsessioncontext instead of thread after the transaction is managed by spring's transactionmanager.
At this point the Hibernate.current_session_context_class should be springsessioncontext, and it will be set automatically when using Localsessionfactorybean.
So I don't need you to set Current_session_context_class.
- - - -- -
Let's analyze Sessionfactoryimpl, org.hibernate.context.spi.CurrentSessionContext .
Org.hibernate.context.internal.ThreadLocalSessionContext
Org.springframework.orm.hibernate4.SpringSessionContext
The source code for these classes
1: Analysis Sessionfactory.getcurrentsession () Let's go in .
come to Sessionfactoryimpl.getcurrentsession () method:
Public final class Sessionfactoryimpl
implements Sessionfactoryimplementor {...
Private final transient currentsessioncontext currentsessioncontext;
. . .
Public Session getcurrentsession () throws Hibernateexception {
if (Currentsessioncontext = = null) {
throw new Hi Bernateexception ("No currentsessioncontext configured!");
}
return currentsessioncontext.currentsession ();
}
. . .
}
The actual type of the Currentsessioncontext property of Sessionfactoryimpl is
Decided by the Hibernate.current_session_context_class ...
2: First set: hibernate.current_session_context_class= Org.hibernate.context.internal.ThreadLocalSessionContext
To this sentence, currentsessioncontext.currentsession () follow in
public class Threadlocalsessioncontext implements Currentsessioncontext {... private static final threadlocal< ;
map> context = newthreadlocal<map> ();
...//Open a session protected session buildorobtainsession () {return factory.withoptions () with "auto-close after transaction commit" . AutoClose (Isautocloseenabled ()). Connectionreleasemode (Getconnectionreleasemode ()).
Flushbeforecompletion (isautoflushenabled ()). Opensession ();
The public final session currentsession () throws Hibernateexception {//from the thread-local volume context tries to remove the Session that has been bound to the thread
Session current = Existingsession (factory); If there is no session bound to the thread (current = = null) {//Opens a "auto-close after transaction commit" session current = Buildorobtainsessio
N ();
Current.gettransaction (). Registersynchronization (Buildcleanupsynch ());
Wrap the session in Thetransaction-protection Proxy if (needswrapping (current)) { Current = wrap (current);
}//The resulting Session is bound to the thread: that is, set to the thread local amount in the <SessionFactory,Session> key value pair context Dobind (current, factory);
} return current; }
. . .
}
the Getcurrentsession () for hibernate.current_session_context_class= thread is now clear:
1: Try to remove the session bound to the thread
2: If not, open a session "auto-close after transaction commit" and add this session to the Threadlocal map.
3: Back to session
3: Then re-analysis: hibernate.current_session_context_class= Org.springframework.orm.hibernate4.SpringSessionContext
Public UserService
{
@Transactional public
void AddUser (user user) throws Exception
{
Session session = Sessionfactory.getcurrentsession ();
Session.save (user);
}
}
since the @transactional was added and the AddUser () method was executed, spring's TransactionManager will automatically open sesion, automatically open transactions, and bind this sesion to Springsessioncontext ( In fact a map of Transactionsynchronizationmanager's threadlocal):
Then to the sessionfactoryimpl.getcurrentsesssion () of the currentsessioncontext.currentsession () This sentence, followed in
public class Springsessioncontext implements Currentsessioncontext {private final sessionfactoryimplementor sessionf
Actory; ------Public Session currentsession () throws Hibernateexception {//The key is this sentence, spring will actually go Transactionsynchron Izationmanager find "currentsession" Object value = Transactionsynchronizationmanager.getresource (this.sessionfactory
);
if (value instanceof session) {return (session) value;
} else if (value instanceof sessionholder) {Sessionholder Sessionholder = (sessionholder) value;
Session session = Sessionholder.getsession (); if (transactionsynchronizationmanager.issynchronizationactive () &&!sessionholder.issynchronizedwit Htransaction ()) {transactionsynchronizationmanager.registersynchronization (new springsess
Ionsynchronization (Sessionholder, this.sessionfactory)); Sessionholder.setsynchronizedwithtransaction (TRUE);
Flushmode Flushmode = Session.getflushmode (); if (Flushmode.ismanualflushmode (flushmode) &&!
Transactionsynchronizationmanager.iscurrenttransactionreadonly ()) {Session.setflushmode (FlushMode.AUTO);
Sessionholder.setpreviousflushmode (Flushmode);
}} return session;
} else if (this.jtasessioncontext! = NULL) {Session session = This.jtaSessionContext.currentSession (); if (transactionsynchronizationmanager.issynchronizationactive ()) {Transactionsynchronizationmanager.reg
Istersynchronization (Newspringflushsynchronization (session));
} return session;
} else {throw new Hibernateexception ("No Session found for current thread"); }
}
}
Object value =transactionsynchronizationmanager.getresource (this. sessionfactory); The key is this sentence, follow in:
Public abstract class Transactionsynchronizationmanager {
...
Private static final threadlocal<map<object, object>> resources;
public static object GetResource (Object key) {
Object actualkey = Transactionsynchronizationutils.unwrapresourceifnecessary (key);
Find the session in the properties resources of Threadlocal, in the resources of <SessionFactory,SessionHolder> or <sessionfactory, Session> Key-value pairs are stored in the map of threadlocal
Object value = Dogetresource (Actualkey);
if (value! = null && logger.istraceenabled ()) {
logger.trace ("retrievedvalue [" + Value + "] for key [" + ACTU Alkey + "] bound to thread [" +
Thread.CurrentThread (). GetName () + "]");
}
return value;
}
. ..
}
Now for hibernate.current_session_context_class= The Org.springframework.orm.hibernate4.SpringSessionContext getcurrentsession () is clear:
1: When @Transactional declared method is executed, spring's TransactionManager will automatically open sesion, automatically open transactions, and bind this sesion to Springsessioncontext ( In fact a map of Transactionsynchronizationmanager's threadlocal):
when the 2:sessionfactory.getcurrentsession () method executes, the call Springsessioncontext.currentsession () finds the current session from the context of the Transactionsynchronizationmanager
3: Returned to the current session, not found, then return Hibernateexception ("No Sessionfound for Present thread")
PS: From this, we also know that when executing sessionfactoryimpl.opensession (), just simply new a sessionbuilder, then call Sessionbuilder.opensession (), The resulting session is not bound to any org.hibernate.context.spi.CurrentSessionContext in the context.
////////////////////////////////////////////////////////////////----------------------------------------------- ----------------------------------------------------------------------------------------
Summary: hibernate.current_session_context_class=thread ( Org.hibernate.context.internal.ThreadLocalSessionContext)
and Hibernate.current_session_context_class=org.springframework.orm.hibernate4.springsessioncontext The difference between the Sessionfactory.getcurrentsession () is:
The former finds the session in the thread-local map of the Threadlocalsessioncontext,
The latter is found in the context of the Springsessioncontext (thethread-local map in the Transactionsynchronizationmanager) .
In the end, you will find that both Threadlocalsessioncontext or springsessioncontext look for "currentsession", all with similar key-value pairs <sessionfactory, The session> form is stored in the threadlocal map, meaning the context of both is a threadlocal map ... Find the corresponding session with the Sessionfactory key, so in the same thread, a sessionfactory can only have one currentsession