The separation of mixed transactions and beans in a deep parsing Java Spring Framework _java

Source: Internet
Author: User
Tags aliases assert mixed sql using java spring framework

Mixed transactions
within the transactions of the ORM Framework's transaction manager, executing SQL using JdbcTemplate is not included in the transaction management.
The following is a source analysis to see why the JdbcTemplate must be used within the Datasourcetransactionmanager transaction.

1. Open the Business
Datasourcetransactionmanager

     protected void Dobegin (Object transaction,transactiondefinition definition) {DATASOURCETRANSACTIONOBJECTT
          Xobject = (datasourcetransactionobject) transaction;
 
          Connection con = null;
                        try {if (txobject.getconnectionholder () = NULL | | Txobject.getconnectionholder (). Issynchronizedwithtransaction ()) {Connectionnewcon = This.dataSource.get
                   Connection (); if (logger.isdebugenabled ()) {Logger.debug ("acquiredconnection [+ Newcon +"] for JDBC transacti
                   On ");
              } txobject.setconnectionholder (Newconnectionholder (Newcon), true);
              } txobject.getconnectionholder (). Setsynchronizedwithtransaction (True);
 
              Con =txobject.getconnectionholder (). getconnection ();
              Integerpreviousisolationlevel = Datasourceutils.prepareconnectionfortransaction (con,definition); Txobject. Setpreviousisolationlevel (Previousisolationlevel); Switch to Manualcommit if necessary.  This is very expensive into some JDBC drivers,//So we don ' t Wantto does it unnecessarily (for example if we ' ve
              Explicitly//configured theconnection pool to set it already).
                   if (Con.getautocommit ()) {Txobject.setmustrestoreautocommit (true); if (logger.isdebugenabled ()) {Logger.debug ("switchingjdbc Connection [+ con +"] to manual Commi
                   T ");
              } con.setautocommit (FALSE);
 
              } txobject.getconnectionholder (). Settransactionactive (True);
              int timeout =determinetimeout (definition); if (timeout!=transactiondefinition.timeout_default) {Txobject.getconnectionholder (). Settimeoutinsecon
              DS (Timeout);
         }//Bind the Sessionholder to the thread.     if (Txobject.isnewconnectionholder ()) {Transactionsynchronizationmanager.bindresource (GETDATASOURC
              E (), Txobject.getconnectionholder ());
              } catch (Exception ex) {datasourceutils.releaseconnection (Con,this.datasource);
          Throw Newcannotcreatetransactionexception ("Could not open JDBC Connection fortransaction", ex);
 }
     }

The Dobegin () method binds the database connection that opened the transaction to a threadlocal variable with the value of the data source named Key,connectionholder (Save the connection).

2. Bound connection

     public static void Bindresource (Objectkey, Object value) throws IllegalStateException {Object Actualkey =
          Transactionsynchronizationutils.unwrapresourceifnecessary (key);
          Assert.notnull (value, "value must not being null");
          Map<object, object> map = Resources.get ();
              Set ThreadLocal map Ifnone found if (map = = null) {map = Newhashmap<object, object> ();
          Resources.set (map);
          Object OldValue = Map.put (Actualkey, value); Transparently suppress aresourceholder that is marked as void ... if (oldValue Instanceofresourceholder &
          & ((Resourceholder) oldValue). Isvoid ()) {oldValue = null; } if (OldValue!= null) {throw newillegalstateexception ("already value [" + OldValue +]] for key
          ["+ actualkey+"] bound to thread ["+ Thread.CurrentThread (). GetName () +"]);
        }  if (logger.istraceenabled ()) {logger.trace ("BoundValue [+ value +"] for key ["+ Actualkey +"] to Thre
          ad["+ thread.currentthread (). GetName () +"] ");
 }
     }

The resources variable is the threadlocal variable mentioned above, so that subsequent jdbctemplate can use DataSource as key to find the database connection.

3. Execute SQL
JdbcTemplate

     Public Objectexecute (PreparedStatementCreator psc, PreparedStatementCallback action) Throwsdataaccesse
          xception {assert.notnull (PSC, "PreparedStatementCreator must not to be null");
          Assert.notnull (Action, "Callback object must not being null");
              if (logger.isdebugenabled ()) {String SQL =getsql (PSC); Logger.debug ("executingprepared SQL statement" + (SQL!= null?)
          "[+ SQL +"] ":"));
          Connection con = datasourceutils.getconnection (Getdatasource ());
          PreparedStatement PS = null;
              try {Connection contouse= con; if (this.nativejdbcextractor!= null && This.nativeJdbcExtractor.isNativeConnectionNecessar
              Yfornativepreparedstatements ()) {contouse =this.nativejdbcextractor.getnativeconnection (con);
              PS =psc.createpreparedstatement (contouse); ApplystatementsettinGS (PS);
              Preparedstatementpstouse = PS; if (this.nativejdbcextractor!= null) {Pstouse =this.nativejdbcextractor.getnativepreparedstatement (PS)
              ;
              Object result =action.doinpreparedstatement (pstouse);
              Handlewarnings (PS);
          return result; catch (SQLException ex) {//releaseconnection early, to avoid potential connection pool Deadloc
              K//In the case Whenthe exception translator hasn ' t been initialized.
              if (PSC instanceofparameterdisposer) {(parameterdisposer) PSC). Cleanupparameters ();
              } String SQL =getsql (PSC);
              PSC = NULL;
              Jdbcutils.closestatement (PS);
              PS = null;
              Datasourceutils.releaseconnection (Con,getdatasource ());
              con = null; Throwgetexceptiontranslator (). Translate ("preparedstatementcallbAck ", SQL,EX); finally {if (PSC instanceofparameterdisposer) {(parameterdisposer) PSC). CLE
              Anupparameters ();
              } jdbcutils.closestatement (PS);
          Datasourceutils.releaseconnection (Con,getdatasource ());
 }
     }


4. Get connection
datasourceutils

    public static Connection Dogetconnection (Datasourcedatasource) throws SQLException {Assert.notnull (Datasou
 
          Rce, "No DataSource specified");
          Connectionholder Conholder = (connectionholder) transactionsynchronizationmanager.getresource (DataSource); if (Conholder!= null&& (conholder.hasconnection) | |
              Conholder.issynchronizedwithtransaction ()) {conholder.requested ());
                   if (!conholder.hasconnection ()) {Logger.debug ("fetchingresumed JDBC Connection from DataSource");
              Conholder.setconnection (Datasource.getconnection ());
          } returnconholder.getconnection ();
 
          /Else We either got Noholder or a empty thread-bound here.
          Logger.debug ("Fetchingjdbc Connection from DataSource");
 
          Connection con =datasource.getconnection (); if (transactionsynchronizationmanager.issynchronizationactive ()) {LoGger.debug ("Registeringtransaction Synchronization for JDBC Connection");
              Use sameconnection for further JDBC actions within the transaction.
              Thread-boundobject'll get removed by synchronization at transaction completion.
              Connectionholderholdertouse = Conholder;
              if (Holdertouse ==null) {holdertouse= new Connectionholder (con);
              else {holdertouse.setconnection (con);
              } holdertouse.requested (); Transactionsynchronizationmanager.registersynchronization (Newconnectionsynchronization (holderToUs
              E, DataSource));
              Holdertouse.setsynchronizedwithtransaction (TRUE);
              if (Holdertouse!=conholder) {transactionsynchronizationmanager.bindresource (datasource,holdertouse);
     } return con;
 }

This shows that Datasourceutils is also through the Transactionsynchronizationmanager to get connected. So as long as JdbcTemplate and Datasourcetransactionmanager have the same datasource, you will be able to get the same database connection, nature can correctly submit, rollback TRANSACTION.

Take hibernate as an example to illustrate the problems mentioned at the beginning, and see why the ORM Framework's transaction manager cannot manage JdbcTemplate.

5 ORM Transaction Manager
Hibernatetransactionmanager

if (Txobject.isnewsessionholder ()) {Transactionsynchronizationmanager.bindresource (Getsessionfactory ()) 
     , Txobject.getsessionholder ()); 
} 

Because the ORM framework does not directly inject datasource into the TransactionManager, it does the same things as the Hibernate transaction manager above, using its own sessionfactory objects to manipulate datasource. So while it may be that the sessionfactory and JdbcTemplate are the same data sources, the different keys are used in the transactionsynchronizationmanager because of the binding One is the sessionfactory name, the other is the DataSource name), so JdbcTemplate does not get the connection to the database on which the ORM transaction manager opened the transaction when executing.


Bean distinction
A spring configuration file in a public project that may be referenced by multiple projects. Because each project may require only a subset of the beans in the public works, the spring container for these projects is started with the need to separate which beans are created.
1. Application instance
in an example configuration in the Apache open source Framework jetspeed: Page-manager.xml
 

 <bean name= "Xmlpagemanager" class= "Org.apache.jetspeed.page.psml.CastorXmlPageManager" init-method= "Init" Destroy-method= "Destroy" > <meta key= "j2:cat" value= "Xmlpagemanager orpageserializer"/> <constructor-arg index= "0" > <ref bean= "idgenerator"/> </constructor-arg> <constructor-arg index= "1" > <ref bean= "Xmldocumenthandlerfactory"/> </constructor-arg> ... </bean> <bean id= "Dbpagemanager" class= "Org.apache.jetspeed.page.impl.DatabasePageManager" init-method= "Init" destroy-method= "destroy" > <meta key= " J2:cat "value=" Dbpagemanager orpageserializer "/> <!--ojb configuration file ResourcePath--> <constructo R-arg index= "0" > <value>JETSPEED-INF/ojb/page-manager-repository.xml</value> </constructor-arg > <!--fragment ID generator--> <constructor-arg index= "1" > <ref bean= "idgenerator"/> </
 Constructor-arg> ... </bean>

When the

2.Bean filter
jetspeedbeandefinitionfilter resolves each bean definition in the spring container, it takes out the j2:cat corresponding value in the above bean configuration. such as Dbpagemanageror Pageserializer. This section is then matched as a regular expression with the current key (read out from the configuration file). Only the matching bean will be created by the spring container.
 
Jetspeedbeandefinitionfilter

 public boolean match (beandefinition BD) {String beancategoriesexpression = (Str
    ing) bd.getattribute (category_meta_key);
    Boolean matched = true; if (beancategoriesexpression!= null) {matched = (Matcher!= null) && Matcher.match (beancategoriesexpre
    Ssion));
return matched; public void Registerdynamicalias (Beandefinitionregistry registry, string beanname,beandefinition BD) {string
    aliases = (String) bd.getattribute (Alias_meta_key);
      if (aliases!= null) {StringTokenizer st = Newstringtokenizer (aliases, ",");
        while (St.hasmoretokens ()) {String alias = St.nexttoken ();
        if (!alias.equals (Beanname)) {Registry.registeralias (beanname, alias); }
      }
    }
  }

The value of the Category_meta_key in the match () method is that the current key is saved in the J2:cat,matcher class and is responsible for matching the current key with the regular expression for each bean.
The Registerdynamicalias function is that after the bean match succeeds, the custom spring container calls this method to register the alias for the Bean. See the source code in the 1.3 below.

3. Custom Spring Container
Customize a spring container, override the Registerbeandefinition () method, and intercept when spring registers the bean.

public class Filteringxmlwebapplicationcontextextends Xmlwebapplicationcontext {private
  
  Jetspeedbeandefinitionfilterfilter; Publicfilteringxmlwebapplicationcontext (jetspeedbeandefinitionfilter filter, string[]configlocations, Properties 
  InitProperties, ServletContext ServletContext) {This (filter, configlocations,initproperties, ServletContext, NULL);  Publicfilteringxmlwebapplicationcontext (jetspeedbeandefinitionfilter filter, string[]configlocations, Properties
    InitProperties, ServletContext servletcontext,applicationcontext parent) {super ();
    if (parent!= null) {this.setparent (parent);
      } if (InitProperties!= null) {propertyplaceholderconfigurer PPC =new propertyplaceholderconfigurer ();
      Ppc.setignoreunresolvableplaceholders (TRUE);
      Ppc.setsystempropertiesmode (Propertyplaceholderconfigurer.system_properties_mode_fallback);
      Ppc.setproperties (InitProperties);
    Addbeanfactorypostprocessor (PPC);
 }   Setconfiglocations (configlocations);
    Setservletcontext (ServletContext);
  This.filter = filter; } protected Defaultlistablebeanfactorycreatebeanfactory () {return new filteringlistablebeanfactory (Filter,geti
  Nternalparentbeanfactory ()); } public Classfilteringlistablebeanfactory extends Defaultlistablebeanfactory {private Jetspeedbeandefinitionfilter
  
  Filter Public Filteringlistablebeanfactory (Jetspeedbeandefinitionfilterfilter, Beanfactory parentbeanfactory) {super (pare
    Ntbeanfactory);
    This.filter = filter;
    if (This.filter = = null) {This.filter = Newjetspeedbeandefinitionfilter ();
  } this.filter.init (); }/** * Override of the Registerbeandefinitionmethod to optionally filter out a beandefinition and * if Requeste D Dynamically register Anbean alias */public void registerbeandefinition (Stringbeanname, beandefinition BD) th
      Rows Beandefinitionstoreexception {if (Filter.match (BD)) {Super.registerbeandefinition (Beanname, BD);
      if (filter!= null) {Filter.registerdynamicalias (this, Beanname, BD);
 }
    }
  }
}

4. Alias for Bean
using the Beanreferencefactorybean factory bean, the two beans (Xmlpagemanager and Dbpagemanager) configured above Wrap it up. The key is assigned to each of the two implementations by configuring the current key. Aliases are all in one, so referencing their bean directly refers to the alias. For example, the following pagelayoutcomponent.
 
Page-manager.xml

<bean class= "Org.springframework.beans.factory.config.BeanReferenceFactoryBean" > <meta key= "j2:cat" value = "Xmlpagemanager"/> <meta key= "J2:alias" value= "Org.apache.jetspeed.page.PageManager"/> <propertyname= "Targetbeanname" value= "Xmlpagemanager"/> </bean> <bean class= " Org.springframework.beans.factory.config.BeanReferenceFactoryBean "> <meta key=" j2:cat "value=" Dbpagemanager "/> <meta key=" J2:alias value= "Org.apache.jetspeed.page.PageManager"/> <propertyname= "Targetbeanname" Value= "Dbpagemanager"/> </bean> <bean id= "org.apache.jetspeed.layout.PageLayoutComponent" class= "ORG.A" Pache.jetspeed.layout.impl.PageLayoutComponentImpl "> <meta key=" j2:cat "value=" Default "/> < Constructor-arg index= "0" > <refbean= "Org.apache.jetspeed.page.PageManager"/> </constructor-arg> ; Constructor-arg index= "1" > <value>jetspeed-layouts::VelocityOneColumn</value> &LT;/constructor-arg> </bean>  

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.