最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入解析Java的Spring框架中的混合事務(wù)與bean的區(qū)分

 更新時(shí)間:2016年01月26日 08:55:25   作者:cdai  
這篇文章主要介紹了Java的Spring框架中的混合事務(wù)與bean的區(qū)分,Spring是Java的SSH三大web開(kāi)發(fā)框架之一,需要的朋友可以參考下

混合事務(wù)
在ORM框架的事務(wù)管理器的事務(wù)內(nèi),使用JdbcTemplate執(zhí)行SQL是不會(huì)納入事務(wù)管理的。
下面進(jìn)行源碼分析,看為什么必須要在DataSourceTransactionManager的事務(wù)內(nèi)使用JdbcTemplate。

1.開(kāi)啟事務(wù)
DataSourceTransactionManager

     protected void doBegin(Object transaction,TransactionDefinition definition) {
          DataSourceTransactionObjecttxObject = (DataSourceTransactionObject) transaction;
          Connection con = null;
 
          try {
              if(txObject.getConnectionHolder() == null ||
                        txObject.getConnectionHolder().isSynchronizedWithTransaction()){
                   ConnectionnewCon = this.dataSource.getConnection();
                   if(logger.isDebugEnabled()) {
                        logger.debug("AcquiredConnection [" + newCon + "] for JDBC transaction");
                   }
                   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 in some JDBC drivers,
              // so we don't wantto do 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 commit");
                   }
                   con.setAutoCommit(false);
              }
              txObject.getConnectionHolder().setTransactionActive(true);
 
              int timeout =determineTimeout(definition);
              if (timeout !=TransactionDefinition.TIMEOUT_DEFAULT) {
                   txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
              }
 
              // Bind the sessionholder to the thread.
              if(txObject.isNewConnectionHolder()) {
                   TransactionSynchronizationManager.bindResource(getDataSource(),txObject.getConnectionHolder());
              }
          }
 
          catch (Exception ex) {
              DataSourceUtils.releaseConnection(con,this.dataSource);
              throw newCannotCreateTransactionException("Could not open JDBC Connection fortransaction", ex);
          }
     }

doBegin()方法會(huì)以數(shù)據(jù)源名為Key,ConnectionHolder(保存著連接)為Value,將已經(jīng)開(kāi)啟事務(wù)的數(shù)據(jù)庫(kù)連接綁定到一個(gè)ThreadLocal變量上。

2.綁定連接

     public static void bindResource(Objectkey, Object value) throws IllegalStateException {
          Object actualKey =TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
          Assert.notNull(value,"Value must not be 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 was 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 thread[" +
                        Thread.currentThread().getName()+ "]");
          }
     }

resources變量就是上面提到的ThreadLocal變量,這樣后續(xù)JdbcTemplate就可以用DataSource作為Key,查找到這個(gè)數(shù)據(jù)庫(kù)連接。

3.執(zhí)行SQL
JdbcTemplate

     public Objectexecute(PreparedStatementCreator psc, PreparedStatementCallback action)
              throwsDataAccessException {
 
          Assert.notNull(psc,"PreparedStatementCreator must not be null");
          Assert.notNull(action,"Callback object must not be 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.isNativeConnectionNecessaryForNativePreparedStatements()){
                   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 deadlock
              // in the case whenthe exception translator hasn't been initialized yet.
              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).cleanupParameters();
              }
              JdbcUtils.closeStatement(ps);
              DataSourceUtils.releaseConnection(con,getDataSource());
          }
     }


4.獲得連接
DataSourceUtils

    public static Connection doGetConnection(DataSourcedataSource) throws SQLException {
          Assert.notNull(dataSource,"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 an empty thread-bound holder 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 will 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(holderToUse, dataSource));
              holderToUse.setSynchronizedWithTransaction(true);
              if (holderToUse !=conHolder) {
                   TransactionSynchronizationManager.bindResource(dataSource,holderToUse);
              }
          }
 
          return con;
     }

由此可見(jiàn),DataSourceUtils也是通過(guò)TransactionSynchronizationManager獲得連接的。所以只要JdbcTemplate與DataSourceTransactionManager有相同的DataSource,就一定能得到相同的數(shù)據(jù)庫(kù)連接,自然就能正確地提交、回滾事務(wù)。
 
再以Hibernate為例來(lái)說(shuō)明開(kāi)篇提到的問(wèn)題,看看為什么ORM框架的事務(wù)管理器不能管理JdbcTemplate。

5 ORM事務(wù)管理器
HibernateTransactionManager

if(txObject.isNewSessionHolder()) { 
     TransactionSynchronizationManager.bindResource(getSessionFactory(),txObject.getSessionHolder()); 
} 

因?yàn)镺RM框架都不是直接將DataSource注入到TransactionManager中使用的,而是像上面Hibernate事務(wù)管理器一樣,使用自己的SessionFactory等對(duì)象來(lái)操作DataSource。所以盡管可能SessionFactory和JdbcTemplate底層都是一樣的數(shù)據(jù)源,但因?yàn)樵赥ransactionSynchronizationManager中綁定時(shí)使用了不同的Key(一個(gè)是sessionFactory名,一個(gè)是dataSource名),所以JdbcTemplate執(zhí)行時(shí)是拿不到ORM事務(wù)管理器開(kāi)啟事務(wù)的那個(gè)數(shù)據(jù)庫(kù)連接的。


bean的區(qū)分
一個(gè)公共工程中的Spring配置文件,可能會(huì)被多個(gè)工程引用。因?yàn)槊總€(gè)工程可能只需要公共工程中的一部分Bean,所以這些工程的Spring容器啟動(dòng)時(shí),需要區(qū)分開(kāi)哪些Bean要?jiǎng)?chuàng)建出來(lái)。
1.應(yīng)用實(shí)例
以Apache開(kāi)源框架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">
   <refbean="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 -->
  <constructor-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>

2.Bean過(guò)濾器
JetspeedBeanDefinitionFilter在Spring容器解析每個(gè)Bean定義時(shí),會(huì)取出上面Bean配置中j2:cat對(duì)應(yīng)的值,例如dbPageManageror pageSerializer。然后將這部分作為正則表達(dá)式與當(dāng)前的Key(從配置文件中讀出)進(jìn)行匹配。只有匹配上的Bean,才會(huì)被Spring容器創(chuàng)建出來(lái)。
 
JetspeedBeanDefinitionFilter

  public boolean match(BeanDefinition bd)
  {
    String beanCategoriesExpression = (String)bd.getAttribute(CATEGORY_META_KEY);
    boolean matched = true;
    if (beanCategoriesExpression != null)
    {
      matched = ((matcher != null)&& matcher.match(beanCategoriesExpression));
    }
    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);
        }
      }
    }
  }

match()方法中的CATEGORY_META_KEY的值就是j2:cat,matcher類(lèi)中保存的就是當(dāng)前的Key,并負(fù)責(zé)將當(dāng)前Key與每個(gè)Bean的進(jìn)行正則表達(dá)式匹配。
registerDynamicAlias的作用是:在Bean匹配成功后,定制的Spring容器會(huì)調(diào)用此方法為Bean注冊(cè)別名。詳見(jiàn)下面1.3中的源碼。

3.定制Spring容器
定制一個(gè)Spring容器,重寫(xiě)registerBeanDefinition()方法,在Spring注冊(cè)Bean時(shí)進(jìn)行攔截。

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,getInternalParentBeanFactory());
  }
}
 
public classFilteringListableBeanFactory extends DefaultListableBeanFactory
{
  private JetspeedBeanDefinitionFilterfilter;
  
  public FilteringListableBeanFactory(JetspeedBeanDefinitionFilterfilter, BeanFactory parentBeanFactory)
  {
    super(parentBeanFactory);
    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 requested dynamically register anbean alias
   */
  public void registerBeanDefinition(StringbeanName, BeanDefinition bd)
      throws BeanDefinitionStoreException
  {
    if (filter.match(bd))
    {
      super.registerBeanDefinition(beanName, bd);
      if (filter != null)
      {
        filter.registerDynamicAlias(this, beanName, bd);
      }
    }
  }
}

4.為Bean起別名
使用BeanReferenceFactoryBean工廠Bean,將上面配置的兩個(gè)Bean(xmlPageManager和dbPageManager)包裝起來(lái)。將Key配成各自的,實(shí)現(xiàn)通過(guò)配置當(dāng)前Key來(lái)切換兩種實(shí)現(xiàn)。別名都配成一個(gè),這樣引用他們的Bean就直接引用這個(gè)別名就行了。例如下面的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.apache.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>
  </constructor-arg>
 </bean> 

相關(guān)文章

  • 在實(shí)踐中了解Java反射機(jī)制應(yīng)用

    在實(shí)踐中了解Java反射機(jī)制應(yīng)用

    當(dāng)程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類(lèi)型,這種語(yǔ)言稱(chēng)為動(dòng)態(tài)語(yǔ)言。我們認(rèn)為java并不是動(dòng)態(tài)語(yǔ)言,但是它卻有一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制,俗稱(chēng):反射。下面我們來(lái)簡(jiǎn)單學(xué)習(xí)一下吧
    2019-05-05
  • 詳解SpringBoot禁用Swagger的三種方式

    詳解SpringBoot禁用Swagger的三種方式

    在生產(chǎn)環(huán)境下,我們需要關(guān)閉swagger配置,避免暴露接口的這種危險(xiǎn)行為。本文就詳細(xì)的介紹了3種情況,感興趣的可以了解一下
    2021-11-11
  • java CompletableFuture實(shí)現(xiàn)異步編排詳解

    java CompletableFuture實(shí)現(xiàn)異步編排詳解

    這篇文章主要為大家介紹了java CompletableFuture實(shí)現(xiàn)異步編排詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Java AQS(AbstractQueuedSynchronizer)源碼解析

    Java AQS(AbstractQueuedSynchronizer)源碼解析

    AbstractQueuedSynchronizer被稱(chēng)為隊(duì)列同步器,簡(jiǎn)稱(chēng)為大家熟知的AQS,這個(gè)類(lèi)可以稱(chēng)作concurrent包的基礎(chǔ)。本文將通過(guò)剖析源碼來(lái)看看AQS是如何工作的,感興趣的可以了解一下
    2023-02-02
  • MyBatis實(shí)現(xiàn)留言板的示例代碼

    MyBatis實(shí)現(xiàn)留言板的示例代碼

    本文主要介紹了MyBatis實(shí)現(xiàn)留言板的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08
  • 詳解Java中super的幾種用法并與this的區(qū)別

    詳解Java中super的幾種用法并與this的區(qū)別

    這篇文章主要介紹了Java中super的幾種用法并與this的區(qū)別,有需要的朋友可以參考一下
    2013-12-12
  • Mybatis動(dòng)態(tài)sql中@Param使用詳解

    Mybatis動(dòng)態(tài)sql中@Param使用詳解

    這篇文章主要介紹了Mybatis動(dòng)態(tài)sql中@Param使用詳解,當(dāng)方法的參數(shù)為非自定義pojo類(lèi)型,且使用了動(dòng)態(tài)sql,那么就需要在參數(shù)前加上@Param注解,需要的朋友可以參考下
    2023-10-10
  • mybatis-xml映射文件及mybatis動(dòng)態(tài)sql詳解

    mybatis-xml映射文件及mybatis動(dòng)態(tài)sql詳解

    XML映射文件的名稱(chēng)與Mapper接口名稱(chēng)一致,并且將XML映射文件和Mapper接口放置在相同包下(同包同名),這篇文章主要介紹了mybatis-xml映射文件及mybatis動(dòng)態(tài)sql的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • Java多線程基礎(chǔ)——Lock類(lèi)

    Java多線程基礎(chǔ)——Lock類(lèi)

    Lock類(lèi)是Java類(lèi)來(lái)提供的功能,豐富的api使得Lock類(lèi)的同步功能比synchronized的同步更強(qiáng)大。本文對(duì)此進(jìn)行詳細(xì)介紹,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • java 中 MD5加密的實(shí)例

    java 中 MD5加密的實(shí)例

    這篇文章主要介紹了java 中 MD5加密的實(shí)例的相關(guān)資料,通過(guò)本文希望能幫助到大家,需要的朋友可以參考下
    2017-09-09

最新評(píng)論

苏州市| 互助| 卓尼县| 兴业县| 凤翔县| 无极县| 济南市| 高台县| 珠海市| 绵阳市| 图木舒克市| 阜宁县| 双桥区| 屯昌县| 临武县| 屯门区| 绩溪县| 麟游县| 颍上县| 玛沁县| 临沭县| 南投市| 乳源| 体育| 安龙县| 罗甸县| 漯河市| 兖州市| 五台县| 县级市| 邳州市| 萍乡市| 岚皋县| 临武县| 湖南省| 出国| 衡水市| 华蓥市| 台南县| 时尚| 泾源县|