Spring origin of Threadlocal-based "resource-transaction" thread binding design

Source: Internet
Author: User

It's a bit of a mouthful, to put it simply, this article wants to explain why Spring chooses to use threadlocal to bind resources and transactions to threads, what the cause and design motivation behind it, and to help you understand spring's thread binding mechanism more clearly through analysis. This text link: http://blog.csdn.net/bluishglc/article/details/7784502 reprint please specify the source!

The "raw" data access notation

Accessing any resource system with transactional characteristics, like a database, has the same characteristics: first you need to get a "pipeline" to access the resources, for the database, this so-called "pipeline" is the connection in JDBC, is the session in Hibernate. And then you'll pass The "Pipeline" releases a series of read and write instructions, such as the SQL of the database, and finally you disconnect the "pipe" and release the connection to the resource. In spring, resources are referred to as "pipelines" that access resources, so JDBC's connection and hibernate sessions are referred to as "resources" (Resource) (this article alternates between these two titles). On the other hand, resources and affairs are closely related, and the opening and submission of affairs are carried out on some "Resource". In hibernate, for example, a "raw" data-access program is often written like this:

Session session = Sessionfactory.opensession ();//get "Resources"Transaction tx =NULL;Try{TX= Session.begintransaction ();//Start a transaction    .... DomainObject DomainObject= Session.load (...);//Data Access Operations..... domainobject.processsomebusinesslogic ();//Business logic Calculation..... session.save (DomainObject);//Another data access operation..... session.save (anotherdomainobject);//Another data access operation..... session.commit ();//Commit a transaction}Catch(RuntimeException e) {tx.rollback (); Throwe;}finally{session.close ();//Freeing Resources}

The idea of the above code is straightforward: first get the database "resources", then start a transaction on the resource, after a series of operations mixed with business computing and data access, commit transactions, release resources.

The problem of layering

Believe that a lot of people can see the above code problem: business logic and data access doping together, committed a layered "taboo." A good layering system tends to implement the code above: using service to implement business logic and using DAO to provide data access support to the service.

Implementation class for a service:

 Public classMyserviceimplImplementsMyService { Public voidprocessbusiness () {//Do you get resources and open transactions here? No!        Will introduce the data access API, "polluting" the Service, destroying the layering! //Session session = Sessionfactory.opensession (); //session.begintransaction ();        .... DomainObject DomainObject= Mydao.getdomainobject (...);//Data Access Operations..... domainobject.processsomebusinesslogic ();//Business logic Calculation..... mydao.save (DomainObject);//Another data access operation..... mydao.save (anotherdomainobject);//Another data access operation        ....            } ....}

A DAO's Hibernate implementation class:

 Public class Implements Mydao {    publicvoid  Save (DomainObject domainobject) {        //  Do you get resources and open transactions here? No! How do you know that this method must be a separate        transaction // and not part of a transaction? Like the service above us.         // Session session = Sessionfactory.opensession ();         // session.begintransaction ();         ....        Session.save (DomainObject);    }        ....}


the focus of the contradiction

From the perspective of "layering", the above scheme is "perfect", but it avoids a practical technical problem: How to place the "get resources" (i.e. session) and "Open transaction" code? As commented in the code, there seems to be a problem where everything looks like an "irreconcilable" contradiction. If we want to solve this "irreconcilable" contradiction, there are two technical problems that need to be solved:

    1. How to conduct transaction delimitation "transparently" (Transaction demarcation)?
    2. How to construct a "context" in which all data access methods can "implicitly" get "the same resource" (Database connection/hibernate Session) when the transaction starts and the transaction commits, and during the transaction. The so-called "implicit" refers to the same resource instance can not be passed to the data access method, otherwise the data access layer of the upper code is subject to the data access proprietary API pollution problem (that is, cracked layered), and the use of global variables is obviously not possible, because the global variable is unique, No application can tolerate the use of only one database connection, especially for a multithreaded Web application environment where a user requests a thread.


The solution of Spring

Spring uses AOP-based declarative transaction delimitation to solve the first problem, while using threadlocal-based resources and transactional thread bindings successfully solves the second problem. (For a concrete implementation of spring, you can refer to my other article: Spring source Parsing (a) the spring transaction control hibernate, the first problem involves the source code is mainly:

Org.springframework.aop.framework.JdkDynamicAopProxy and Org.springframework.transaction.interceptor.TransactionInterceptor

The main source of the second problem is:

Org.springframework.transaction.support.AbstractPlatformTransactionManager and Org.springframework.transaction.support.TransactionSynchronizationManager)


This article focuses on how spring solves the second problem, with two points that need to be specifically explained:

    1. "Context": Spring uses "thread context", or treadlocal, for a very simple reason, as a thread-scoped variable that is well-known as "implicit", that is, the variable can be directly obtained under the current thread (avoiding parameter passing). At the same time, the scope is not as large as global variables and there is only one instance globally. In fact, from a larger context, most of the spring applications for the B/s architecture of the Web application, affected by the servlet threading model, such a Web application is a user request to open a new thread for processing, in this context, Spring is a very appropriate way to handle resources and transactions in a thread-bound context.
    2. "Resource and Transaction life cycle": if only from the literal understanding of "thread binding", it is easy to misunderstand that the lifetime and thread of the resource and transaction bound to the thread are equal length, which is wrong. In fact, the life cycle of resources and transactions is not necessarily associated with the thread life cycle, but when resources and transactions exist, they are bound to threads in the form of treadlocal. The life cycle of the resource and the life cycle of the transaction are equal, we call the resource-transaction life cycle Relationship: Connection-per-transaction or session-per-transaction.


Hibernate self-clothed

As a short episode, we talked about hibernate. In order to meet the general demand for Session-per-transaction, Hibernate has also realized its own session-per-transaction model, is known as sessionfactory.getcurrentsession (), the method returns the session instance bound on the current thread, if the current thread does not have a session instance, Creates a new instance that is bound to the current thread in the form of Threadlocal, and the session generated by the method is actually a session proxy that attaches the following action to the internal actual session:

    1. Intercept the data manipulation method of the session, confirming that a transaction has been invoked before Begaintranscation () has been called before executing the operation, or an exception will be thrown. This ensures that the use of the session must always begin with the creation of a transaction.
    2. The session is automatically closed when the transaction is in commit or rollback. This ensures that the session will not be available after the transaction is committed.

It is these two points that ensure that the session and the transaction maintain a consistent life cycle.

That's how it all goes.

In combination with the above scenario and the spring solution, a well-layered program is implemented with spring declarative transactions, and its resources and transactions work under the control of spring:

    1. If the current thread executes a method that requires transaction control (such as a service's method), through AOP interception, spring will request a database connection or a hibernate session before the method executes.
    2. Once the resource is successfully obtained, a transaction is opened.
    3. Storing the resource as a database connection or an instance of Hibernate session in the current thread's threadlocal (that is, thread binding)
    4. During the execution of the method, any place that requires a database connection or hibernate session for data access is removed from the current thread's threadlocal with the same database connection or an instance of Hibernate session ( This action is implemented by the various template classes provided by spring.
    5. The method execution ends, also through AOP interception, Spring takes out the transaction bound to the current thread (for hibernate it is to take out the binding on the current thread on the previous Sessionholder instance, which holds the current session and transaction instance), Execute the submission.
    6. After the transaction is committed, release the resources and clear all the objects bound on the front line!
    7. If a new transaction is initiated after the thread, everything will start again, and Spring will start a new transaction with a new database connection or Hibernate session instance, with no relationship between the two transactions.


A little summary.

      1. Connection-per-transaction/session-per-transaction is almost always what you need.
      2. In a layered architecture, where some variables or objects do need to work across layers (such as connection/session/transaction in this example), you might need a "context" (or a cross-layer scope) to hold the variable or object, avoiding the argument "In the form of passing it between tiers, the thread-local variable threadlocal may be exactly what you need.

Spring origin of Threadlocal-based "resource-transaction" thread binding design

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.