When we call a method of the service layer, it ensures that all updates to the database that we perform in this method remain in one transaction, and that the methods that are invoked within the transaction layer either succeed or fail altogether. Then the communication characteristics of the business are also mentioned here. If you are in this method of your service layer, in addition to calling the methods of this class of DAO layer, and invoking other service methods, then the other service method is called to solve the problem: "Transactions are propagated." In spring there are multiple configurations for propagation characteristics, and in most cases we use only one of them: propgation_required, this configuration means that when I invoke the service layer method, I open a transaction (the method that calls that layer begins to create the transaction, Depends on your AOP configuration), then when invoking the other methods in this service layer, create a new transaction if the current method produces a transaction with the current method. This work is made by spring to help us do it.
We had to manually control the transaction without spring helping us to complete the transaction, for example, when we were using hibernate only in our project, instead of integrating into spring, we called other business logic methods in a service layer, In order to ensure that things must also pass the current Hibernate session to the next method, or by using the Threadlocal method, passing the session to the next method is actually a goal. Now that the work is done by spring, we can focus more on our business logic. Without having to worry about the issues of the business. By default, when runtimeexception occurs, the transaction is rolled back, so be aware that if you have your own exception handling mechanism to define your own exception in the event of a program error, Such a transaction must be inherited from the RuntimeException class before it can be rolled back.
When we use Hibernate as a class library for database operations, we generally work with database-related operations in the DAO layer and write business logic in the service layer. But if our project is relatively small, then it is possible to write the transaction directly in the DAO layer, this is to see the individual, there is no special rules. However, if the project is relatively large, then DAO should only do simple database operations, service write transaction operations, that is, the entire business logic.
For example, the business logic requires adding a user to the user table in the database and adding a log to the log table, which requires the invocation of two methods of DAO (Userdao Saveuser and Logdao savelog). This is obviously a transaction, which is to roll back to the initial state if there is a problem with the operation. So how to control transactions at the service level, this article is illustrated with this example code.
Problems with session transactions in DAO
Let's look at the business of writing Hibernate's session in the DAO layer first.
Package com.xxg;
Import Org.hibernate.SessionFactory;
Import org.hibernate.cfg.Configuration;
public class Hibernateutil {
private static final Sessionfactory sessionfactory = Buildsessionfactory ();
private static Sessionfactory buildsessionfactory () {
try {
Create the sessionfactory from Hibernate.cfg.xml
return new Configuration (). Configure (). Buildsessionfactory ();
}
catch (Throwable ex) {
Make sure your log the exception, as it might be swallowed
System.err.println ("Initial sessionfactory creation failed." + ex);
throw new Exceptionininitializererror (ex);
}
}
public static Sessionfactory Getsessionfactory () {
return sessionfactory;
}
}
Create user Tables T_user (id,username) and log table T_log (Id,content), and their corresponding entity classes user, log, and mapping files, where the code is not posted.
public class Userdao {
public void saveuser (user user) {
& nbsp; sessionfactory sessionfactory = Hibernateutil.getsessionfactory (); Get Sessionfactory
Session session = Sessionfactory.opensession ();//Opensession
Session.begintransaction (); Start transaction
session.save (user);
session.gettransaction (). commit (); Transaction Submission
session.close ();//close session
}
}
public class Logdao {
public void Savelog (log log) {
Sessionfactory sessionfactory = Hibernateutil.getsessionfactory (); Get Sessionfactory
Session session = Sessionfactory.opensession ();//Opensession
Session.begintransaction (); Start a transaction
Session.save (log);
Session.gettransaction (). commit (); Transaction commit
Session.close (); Close session
}
}
Next we'll look at writing a business logic in the service
public class Testservice {
public void Save (user user) {
Userdao Userdao = new Userdao ();
Userdao.saveuser (user);
Logdao Logdao = new Logdao ();
Log log = new log ();
Log.setcontent ("Insert a user");
Logdao.savelog (log);
}
}
As you can see, we wrote the database transactions in two DAO, highlighted in the Code, and Session.begintransaction () shows the beginning of the declared transaction.
This is wrong, because these two things are done as a transaction, there will be a successful commit of one transaction, and the other may fail, resulting in an inconsistency, so that these two operations are not a transaction transaction, so the write is a failed transaction.
Therefore, we want to declare the transaction in the service.
A database transaction that writes a session at the service layer
In order to put transactions in service, we need to change the code of Hibernateutil to be implemented. Otherwise, using the one above does not meet our needs. In this new Hibernateutil code, a local variable inside the threadlocal thread is used to save the Hibernate session object. This allows you to use the same session object in different classes without passing parameters.
public class Hibernateutil {
public static final ThreadLocal session = new ThreadLocal ((www.111cn.net));
public static final Sessionfactory sessionfactory;
static {
try {
Sessionfactory = new Configuration (). Configure (). Buildsessionfactory ();
} catch (Throwable ex) {
throw new Exceptionininitializererror (ex);
}
}
public static Session Currentsession () throws Hibernateexception
{
Session s = session.get ();
if (s = = null)
{
s = sessionfactory.opensession ();
Session.set (s);
}
return (s);
}
public static void CloseSession () throws Hibernateexception
{
Session s = session.get ();
if (s! = null)
{
S.close ();
}
Session.set (NULL);
}
}
Next, we put the transaction in the service. Look at the code:
public class Testservice {
public void Save (user user) {
Sessionfactory sessionfactory = Hibernateutil.getsessionfactory (); Get Sessionfactory
Session session = Sessionfactory.getcurrentsession ();//getcurrentsession
Session.begintransaction ();//Transaction start
Userdao Userdao = new Userdao ();
Userdao.saveuser (user);
Logdao Logdao = new Logdao ();
Log log = new log ();
Log.setcontent ("Insert a user");
Logdao.savelog (log);
Session.gettransaction (). commit ();//Transaction commit
}
}
public class Logdao {
public void Savelog (log log) throws Runtimeexceptio n{
sessionfactory sessionfactory = Hibernateutil.getsessionfactory (); Get Sessionfactory
Session session = Sessionfactory.getcurrentsession (); Getcurrentsession
session.save (log);
throw new RuntimeException ();
}
}
public class Userdao {
public void Saveuser (user user) {
Sessionfactory sessionfactory = Hibernateutil.getsessionfactory (); Get Sessionfactory
Session session = Sessionfactory.getcurrentsession ();//getcurrentsession
Session.save (user);
}
}
The session object of the current thread can be obtained through getcurrentsession (), which is used to share the session. The transaction begins with the service, and then the service ends.
Getcurrentsession () differs from opensession ()
The session created by Getcurrentsession is bound to the current thread, and Opensession does not.
The thread created by Getcurrentsession automatically shuts down after a transaction is rolled back or the thing commits, and opensession must be closed manually
A session created with getcurrentsession () is bound to the current thread, with Opensession ()
The session created will not
* Session created with Getcurrentsession () is automatically closed on commit or rollback, and opensession () is used
The session created must be manually closed
2, using getcurrentsession () need to add the following configuration in the Hibernate.cfg.xml file:
* If you are using a local transaction (JDBC Transaction)
<property name= "Hibernate.current_session_context_class" >thread</property>
* If you are using a global transaction (JTA Transaction)
<property name= "Hibernate.current_session_context_class" >jta</property>
Getcurrentsession () association with Opensession ()
When the sessionfactory is started, Hibernate will create the corresponding Currentsessioncontext according to the configuration, and when the Getcurrentsession () is called, the actual method to be executed is Currentsessioncontext.currentsession (). When Currentsession () executes, currentsession calls Sessionfactory opensession if the current Session is empty. So Getcurrentsession () is a better way to get a Session for Java EE.
From:http://www.111cn.net/jsp/java/85451.htm