国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - 深入解析Java的Spring框架中的混合事務(wù)與bean的區(qū)分

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

2020-03-24 13:23cdai JAVA教程

這篇文章主要介紹了Java的Spring框架中的混合事務(wù)與bean的區(qū)分,Spring是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下

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

1.開啟事務(wù)
DataSourceTransactionManager

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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)開啟事務(wù)的數(shù)據(jù)庫連接綁定到一個(gè)ThreadLocal變量上。

2.綁定連接

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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ù)庫連接。

3.執(zhí)行SQL
JdbcTemplate

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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;
 }

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

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

?
1
2
3
if(txObject.isNewSessionHolder()) {
     TransactionSynchronizationManager.bindResource(getSessionFactory(),txObject.getSessionHolder());
}

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


bean的區(qū)分
一個(gè)公共工程中的Spring配置文件,可能會(huì)被多個(gè)工程引用。因?yàn)槊總€(gè)工程可能只需要公共工程中的一部分Bean,所以這些工程的Spring容器啟動(dòng)時(shí),需要區(qū)分開哪些Bean要?jiǎng)?chuàng)建出來。
1.應(yīng)用實(shí)例
以Apache開源框架Jetspeed中的一段配置為例:page-manager.xml
 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<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過濾器
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)建出來。
 
JetspeedBeanDefinitionFilter

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  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類中保存的就是當(dāng)前的Key,并負(fù)責(zé)將當(dāng)前Key與每個(gè)Bean的進(jìn)行正則表達(dá)式匹配。
registerDynamicAlias的作用是:在Bean匹配成功后,定制的Spring容器會(huì)調(diào)用此方法為Bean注冊(cè)別名。詳見下面1.3中的源碼。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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)包裝起來。將Key配成各自的,實(shí)現(xiàn)通過配置當(dāng)前Key來切換兩種實(shí)現(xiàn)。別名都配成一個(gè),這樣引用他們的Bean就直接引用這個(gè)別名就行了。例如下面的PageLayoutComponent。
 
page-manager.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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>

 

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产资源在线播放 | 一区二区不卡视频 | 中文字幕视频在线 | 国产中文视频 | 免费在线观看黄色网址 | 日本jizz在线观看 | 日韩在线视频观看 | 欧美综合色 | 韩国精品一区二区三区 | 中文字幕欧美激情 | 中文字幕乱码视频32 | 亚洲伊人久久综合 | 亚洲一区视频在线 | 国产欧美久久久久久 | 亚洲视频免费看 | 国产乱码一区二区三区 | 久久99综合久久爱伊人 | 精品伦精品一区二区三区视频 | 久久er99热精品一区二区 | 国产一区二区欧美 | 在线欧美亚洲 | 中文字幕在线电影观看 | 日本精品一区二 | 久久久久国产 | 日韩精品| 国产欧美日韩一区二区三区 | 久久伊人精品 | 免费激情| 成人免费在线视频 | 欧美一区二区视频免费观看 | 日本精品视频在线观看 | 国产天堂 | 日日夜夜精品免费视频 | 成人免费在线电影 | 国产98色在线 | 日韩 | 成人日韩视频 | 亚洲欧美在线观看 | 毛片网页| 久久99精品久久久久久园产越南 | 99久久视频 | 中文字幕日韩视频 |