京山游俠

          專注技術(shù),拒絕扯淡
          posts - 50, comments - 868, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
          在SpringSide 3 中,白衣提供的預(yù)先配置好的環(huán)境非常有利于用戶進(jìn)行快速開發(fā),但是同時(shí)也會(huì)為擴(kuò)展帶來一些困難。最直接的例子就是關(guān)于在項(xiàng)目中使用多個(gè)數(shù)據(jù)源的問題,似乎很難搞。在上一篇中,我探討了SpringSide 3 中的數(shù)據(jù)訪問層,在這一篇中,我立志要解決多數(shù)據(jù)源配置的難題,我的思路是這樣的:

          第一步、測(cè)試能否配置多個(gè)DataSource
          第二步、測(cè)試能否配置多個(gè)SessionFactory
          第三步、測(cè)試能否配置多個(gè)TransactionManager
          第四步、測(cè)試能否使用多個(gè)TransactionManager,也就是看能否配置多個(gè)<tx:annotation-driven/>

          基本上到第四步就應(yīng)該走不通了,因?yàn)镾pring中似乎不能配置多個(gè)<tx:annotation-driven/>,而且@transactional注解也無法讓用戶選擇具體使用哪個(gè)TransactionManager。也就是說,在SpringSide的應(yīng)用中,不能讓不同的數(shù)據(jù)源分別屬于不同的事務(wù)管理器,多數(shù)據(jù)源只能使用分布式事務(wù)管理器,那么測(cè)試思路繼續(xù)如下進(jìn)行:

          第五步、測(cè)試能否配置JTATransactionManager

          如果到這一步,項(xiàng)目還能順利在Tomcat中運(yùn)行的話,我們就算大功告成了。但我總認(rèn)為事情不會(huì)那么順利,我總覺得JTATransactionManager需要應(yīng)用服務(wù)器的支持,而且需要和JNDI配合使用,具體是不是這樣,那只有等測(cè)試后才知道。如果被我不幸言中,那么進(jìn)行下一步:

          第六步、更換Tomcat為GlassFish,更換JDBC的DataSource為JNDI查找的DataSource,然后配置JTATransactionManager

          下面測(cè)試開始,先假設(shè)場(chǎng)景,還是繼續(xù)用上一篇中提到的簡(jiǎn)單的文章發(fā)布系統(tǒng),假設(shè)該系統(tǒng)運(yùn)行一段時(shí)間后非常火爆,單靠一臺(tái)服務(wù)器已經(jīng)無法支持巨大的用戶數(shù),這時(shí)候,站長(zhǎng)想到了把數(shù)據(jù)進(jìn)行水平劃分,于是,需要建立一個(gè)索引數(shù)據(jù)庫,該索引數(shù)據(jù)庫需保存每一篇文章的Subject及其內(nèi)容所在的Web服務(wù)器,而每一個(gè)Web服務(wù)器上運(yùn)行的項(xiàng)目,需要同時(shí)訪問索引數(shù)據(jù)庫和內(nèi)容數(shù)據(jù)庫。所以,需要?jiǎng)?chuàng)建索引數(shù)據(jù)庫,如下:
          create database puretext_index;

          use puretext_index;

          create table articles(
          id 
          int primary key auto_increment,
          subject 
          varchar(256),
          webserver 
          varchar(30)
          );

          第一步測(cè)試,配置多個(gè)DataSource,配置文件如下:
          application.properties:
          jdbc.urlContent=jdbc:mysql://localhost:3306/PureText?useUnicode=true&characterEncoding=utf8
          jdbc.urlIndex
          =jdbc:mysql://localhost:3306/PureText_Index?useUnicode=true&characterEncoding=utf8

          applicationContext.xml:
          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:jee
          ="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
              xmlns:context
          ="http://www.springframework.org/schema/context"
              xsi:schemaLocation
          ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
              default-lazy-init
          ="true">

              
          <description>Spring公共配置文件 </description>

              
          <!-- 定義受環(huán)境影響易變的變量 -->
              
          <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                  
          <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
                  
          <property name="ignoreResourceNotFound" value="true" />
                  
          <property name="locations">
                      
          <list>
                          
          <!-- 標(biāo)準(zhǔn)配置 -->
                          
          <value>classpath*:/application.properties</value>
                          
          <!-- 本地開發(fā)環(huán)境配置 -->
                          
          <value>classpath*:/application.local.properties</value>
                          
          <!-- 服務(wù)器生產(chǎn)環(huán)境配置 -->
                          
          <!-- <value>file:/var/myapp/application.server.properties</value> -->
                      
          </list>
                  
          </property>
              
          </bean>

              
          <!-- 使用annotation 自動(dòng)注冊(cè)bean,并保證@Required,@Autowired的屬性被注入 -->
              
          <context:component-scan base-package="cn.puretext" />

              
          <!-- 數(shù)據(jù)源配置,使用應(yīng)用內(nèi)的DBCP數(shù)據(jù)庫連接池 -->
              
          <bean id="dataSourceContent" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
                  
          <!-- Connection Info -->
                  
          <property name="driverClassName" value="com.mysql.jdbc.Driver" />
                  
          <property name="url" value="${jdbc.urlContent}" />
                  
          <property name="username" value="${jdbc.username}" />
                  
          <property name="password" value="${jdbc.password}" />

                  
          <!-- Connection Pooling Info -->
                  
          <property name="initialSize" value="5" />
                  
          <property name="maxActive" value="100" />
                  
          <property name="maxIdle" value="30" />
                  
          <property name="maxWait" value="1000" />
                  
          <property name="poolPreparedStatements" value="true" />
                  
          <property name="defaultAutoCommit" value="false" />
              
          </bean>
              
          <bean id="dataSourceIndex" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
                  
          <!-- Connection Info -->
                  
          <property name="driverClassName" value="com.mysql.jdbc.Driver" />
                  
          <property name="url" value="${jdbc.urlIndex}" />
                  
          <property name="username" value="${jdbc.username}" />
                  
          <property name="password" value="${jdbc.password}" />

                  
          <!-- Connection Pooling Info -->
                  
          <property name="initialSize" value="5" />
                  
          <property name="maxActive" value="100" />
                  
          <property name="maxIdle" value="30" />
                  
          <property name="maxWait" value="1000" />
                  
          <property name="poolPreparedStatements" value="true" />
                  
          <property name="defaultAutoCommit" value="false" />
              
          </bean>

              
          <!-- 數(shù)據(jù)源配置,使用應(yīng)用服務(wù)器的數(shù)據(jù)庫連接池 -->
              
          <!--<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ExampleDB" />-->

              
          <!-- Hibernate配置 -->
              
          <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
                  
          <property name="dataSource" ref="dataSourceContent" />
                  
          <property name="namingStrategy">
                      
          <bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
                  
          </property>
                  
          <property name="hibernateProperties">
                      
          <props>
                          
          <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                          
          <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                          
          <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                          
          <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
                          
          </prop>
                          
          <prop key="hibernate.cache.provider_configuration_file_resource_path">${hibernate.ehcache_config_file}</prop>
                      
          </props>
                  
          </property>
                  
          <property name="packagesToScan" value="cn.puretext.entity.*" />
              
          </bean>

              
          <!-- 事務(wù)管理器配置,單數(shù)據(jù)源事務(wù) -->
              
          <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                  
          <property name="sessionFactory" ref="sessionFactory" />
              
          </bean>

              
          <!-- 事務(wù)管理器配置,多數(shù)據(jù)源JTA事務(wù)-->
              
          <!--
                  <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager or
                  WebLogicJtaTransactionManager" />
              
          -->

              
          <!-- 使用annotation定義事務(wù) -->
              
          <tx:annotation-driven transaction-manager="transactionManager" />
          </beans>

          這個(gè)時(shí)候運(yùn)行上一篇文章中寫好的單元測(cè)試DaoTest.java,結(jié)果發(fā)現(xiàn)還是會(huì)出錯(cuò),錯(cuò)誤原因如下:
          org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cn.puretext.unit.service.DaoTest': Autowiring of methods failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests.setDataSource(javax.sql.DataSource); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: [dataSourceContent, dataSourceIndex]

          經(jīng)過分析,發(fā)現(xiàn)是測(cè)試類的基類需要注入DataSource,而現(xiàn)在配置了多個(gè)DataSource,所以Spring不知道哪個(gè)DataSource匹配了,所以需要改寫DaoTest.java,如下:
          package cn.puretext.unit.service;

          import java.util.List;

          import javax.annotation.Resource;
          import javax.sql.DataSource;

          import org.junit.Test;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springside.modules.orm.Page;
          import org.springside.modules.test.junit4.SpringTxTestCase;

          import cn.puretext.dao.ArticleDao;
          import cn.puretext.entity.web.Article;

          public class DaoTest extends SpringTxTestCase {
              @Autowired
              
          private ArticleDao articleDao;
              
              
          public ArticleDao getArticleDao() {
                  
          return articleDao;
              }

              
          public void setArticleDao(ArticleDao articleDao) {
                  
          this.articleDao = articleDao;
              }

              @Override
              @Resource(name 
          = "dataSourceContent")
              
          public void setDataSource(DataSource dataSource) {
                  
          // TODO Auto-generated method stub
                  super.setDataSource(dataSource);
              }

              @Test
              
          public void addArticle() {
                  Article article 
          = new Article();
                  article.setSubject(
          "article test");
                  article.setContent(
          "article test");
                  articleDao.save(article);
              }
              
              @Test
              
          public void pageQuery() {
                  Page
          <Article> page = new Page<Article>();
                  page.setPageSize(
          10);
                  page.setPageNo(
          2);
                  page 
          = articleDao.getAll(page);
                  List
          <Article> articles = page.getResult();
              }
          }

           改變的內(nèi)容主要為重寫了基類中的setDataSource方法,并使用@Resource注解指定使用的DataSource為dataSourceContent。經(jīng)過修改后,單元測(cè)試成功運(yùn)行。

          第二步,配置多個(gè)SessionFactory,配置文件如下:
          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:jee
          ="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
              xmlns:context
          ="http://www.springframework.org/schema/context"
              xsi:schemaLocation
          ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
              default-lazy-init
          ="true">

              
          <description>Spring公共配置文件 </description>

              
          <!-- 定義受環(huán)境影響易變的變量 -->
              
          <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                  
          <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
                  
          <property name="ignoreResourceNotFound" value="true" />
                  
          <property name="locations">
                      
          <list>
                          
          <!-- 標(biāo)準(zhǔn)配置 -->
                          
          <value>classpath*:/application.properties</value>
                          
          <!-- 本地開發(fā)環(huán)境配置 -->
                          
          <value>classpath*:/application.local.properties</value>
                          
          <!-- 服務(wù)器生產(chǎn)環(huán)境配置 -->
                          
          <!-- <value>file:/var/myapp/application.server.properties</value> -->
                      
          </list>
                  
          </property>
              
          </bean>

              
          <!-- 使用annotation 自動(dòng)注冊(cè)bean,并保證@Required,@Autowired的屬性被注入 -->
              
          <context:component-scan base-package="cn.puretext" />

              
          <!-- 數(shù)據(jù)源配置,使用應(yīng)用內(nèi)的DBCP數(shù)據(jù)庫連接池 -->
              
          <bean id="dataSourceContent" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
                  
          <!-- Connection Info -->
                  
          <property name="driverClassName" value="com.mysql.jdbc.Driver" />
                  
          <property name="url" value="${jdbc.urlContent}" />
                  
          <property name="username" value="${jdbc.username}" />
                  
          <property name="password" value="${jdbc.password}" />

                  
          <!-- Connection Pooling Info -->
                  
          <property name="initialSize" value="5" />
                  
          <property name="maxActive" value="100" />
                  
          <property name="maxIdle" value="30" />
                  
          <property name="maxWait" value="1000" />
                  
          <property name="poolPreparedStatements" value="true" />
                  
          <property name="defaultAutoCommit" value="false" />
              
          </bean>
              
          <bean id="dataSourceIndex" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
                  
          <!-- Connection Info -->
                  
          <property name="driverClassName" value="com.mysql.jdbc.Driver" />
                  
          <property name="url" value="${jdbc.urlIndex}" />
                  
          <property name="username" value="${jdbc.username}" />
                  
          <property name="password" value="${jdbc.password}" />

                  
          <!-- Connection Pooling Info -->
                  
          <property name="initialSize" value="5" />
                  
          <property name="maxActive" value="100" />
                  
          <property name="maxIdle" value="30" />
                  
          <property name="maxWait" value="1000" />
                  
          <property name="poolPreparedStatements" value="true" />
                  
          <property name="defaultAutoCommit" value="false" />
              
          </bean>

              
          <!-- 數(shù)據(jù)源配置,使用應(yīng)用服務(wù)器的數(shù)據(jù)庫連接池 -->
              
          <!--<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ExampleDB" />-->

              
          <!-- Hibernate配置 -->
              
          <bean id="sessionFactoryContent" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
                  
          <property name="dataSource" ref="dataSourceContent" />
                  
          <property name="namingStrategy">
                      
          <bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
                  
          </property>
                  
          <property name="hibernateProperties">
                      
          <props>
                          
          <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                          
          <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                          
          <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                          
          <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
                          
          </prop>
                          
          <prop key="hibernate.cache.provider_configuration_file_resource_path">${hibernate.ehcache_config_file}</prop>
                      
          </props>
                  
          </property>
                  
          <property name="packagesToScan" value="cn.puretext.entity.*" />
              
          </bean>
              
          <bean id="sessionFactoryIndex" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
                  
          <property name="dataSource" ref="dataSourceIndex" />
                  
          <property name="namingStrategy">
                      
          <bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
                  
          </property>
                  
          <property name="hibernateProperties">
                      
          <props>
                          
          <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                          
          <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                          
          <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                          
          <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
                          
          </prop>
                          
          <prop key="hibernate.cache.provider_configuration_file_resource_path">${hibernate.ehcache_config_file}</prop>
                      
          </props>
                  
          </property>
                  
          <property name="packagesToScan" value="cn.puretext.entity.*" />
              
          </bean>

              
          <!-- 事務(wù)管理器配置,單數(shù)據(jù)源事務(wù) -->
              
          <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                  
          <property name="sessionFactory" ref="sessionFactoryContent" />
              
          </bean>

              
          <!-- 事務(wù)管理器配置,多數(shù)據(jù)源JTA事務(wù)-->
              
          <!--
                  <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager or
                  WebLogicJtaTransactionManager" />
              
          -->

              
          <!-- 使用annotation定義事務(wù) -->
              
          <tx:annotation-driven transaction-manager="transactionManager" />
          </beans>

          運(yùn)行單元測(cè)試,報(bào)錯(cuò),錯(cuò)誤代碼如下:
          org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cn.puretext.unit.service.DaoTest': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private cn.puretext.dao.ArticleDao cn.puretext.unit.service.DaoTest.articleDao; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'articleDao': Autowiring of methods failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springside.modules.orm.hibernate.SimpleHibernateDao.setSessionFactory(org.hibernate.SessionFactory); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.hibernate.SessionFactory] is defined: expected single matching bean but found 2: [sessionFactoryContent, sessionFactoryIndex]

          這和上面出現(xiàn)的錯(cuò)誤是異曲同工的,只不過這次是ArticleDao類里面不知道注入哪一個(gè)SessionFactory,因此,需要修改ArticleDao類,重寫setSessionFactory方法,并用@Resource注解指定,如下:
          package cn.puretext.dao;


          import javax.annotation.Resource;

          import org.hibernate.SessionFactory;
          import org.springframework.stereotype.Repository;
          import org.springside.modules.orm.hibernate.HibernateDao;

          import cn.puretext.entity.web.Article;

          @Repository
          public class ArticleDao extends HibernateDao<Article, Long> {

              @Override
              @Resource(name 
          = "sessionFactoryContent")
              
          public void setSessionFactory(SessionFactory sessionFactory) {
                  
          // TODO Auto-generated method stub
                  super.setSessionFactory(sessionFactory);
              }

          }

          運(yùn)行單元測(cè)試,成功。

          第三步、配置多個(gè)TransactionManager,如下:
          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:jee
          ="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
              xmlns:context
          ="http://www.springframework.org/schema/context"
              xsi:schemaLocation
          ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
              default-lazy-init
          ="true">

              
          <description>Spring公共配置文件 </description>

              
          <!-- 定義受環(huán)境影響易變的變量 -->
              
          <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                  
          <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
                  
          <property name="ignoreResourceNotFound" value="true" />
                  
          <property name="locations">
                      
          <list>
                          
          <!-- 標(biāo)準(zhǔn)配置 -->
                          
          <value>classpath*:/application.properties</value>
                          
          <!-- 本地開發(fā)環(huán)境配置 -->
                          
          <value>classpath*:/application.local.properties</value>
                          
          <!-- 服務(wù)器生產(chǎn)環(huán)境配置 -->
                          
          <!-- <value>file:/var/myapp/application.server.properties</value> -->
                      
          </list>
                  
          </property>
              
          </bean>

              
          <!-- 使用annotation 自動(dòng)注冊(cè)bean,并保證@Required,@Autowired的屬性被注入 -->
              
          <context:component-scan base-package="cn.puretext" />

              
          <!-- 數(shù)據(jù)源配置,使用應(yīng)用內(nèi)的DBCP數(shù)據(jù)庫連接池 -->
              
          <bean id="dataSourceContent" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
                  
          <!-- Connection Info -->
                  
          <property name="driverClassName" value="com.mysql.jdbc.Driver" />
                  
          <property name="url" value="${jdbc.urlContent}" />
                  
          <property name="username" value="${jdbc.username}" />
                  
          <property name="password" value="${jdbc.password}" />

                  
          <!-- Connection Pooling Info -->
                  
          <property name="initialSize" value="5" />
                  
          <property name="maxActive" value="100" />
                  
          <property name="maxIdle" value="30" />
                  
          <property name="maxWait" value="1000" />
                  
          <property name="poolPreparedStatements" value="true" />
                  
          <property name="defaultAutoCommit" value="false" />
              
          </bean>
              
          <bean id="dataSourceIndex" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
                  
          <!-- Connection Info -->
                  
          <property name="driverClassName" value="com.mysql.jdbc.Driver" />
                  
          <property name="url" value="${jdbc.urlIndex}" />
                  
          <property name="username" value="${jdbc.username}" />
                  
          <property name="password" value="${jdbc.password}" />

                  
          <!-- Connection Pooling Info -->
                  
          <property name="initialSize" value="5" />
                  
          <property name="maxActive" value="100" />
                  
          <property name="maxIdle" value="30" />
                  
          <property name="maxWait" value="1000" />
                  
          <property name="poolPreparedStatements" value="true" />
                  
          <property name="defaultAutoCommit" value="false" />
              
          </bean>

              
          <!-- 數(shù)據(jù)源配置,使用應(yīng)用服務(wù)器的數(shù)據(jù)庫連接池 -->
              
          <!--<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ExampleDB" />-->

              
          <!-- Hibernate配置 -->
              
          <bean id="sessionFactoryContent" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
                  
          <property name="dataSource" ref="dataSourceContent" />
                  
          <property name="namingStrategy">
                      
          <bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
                  
          </property>
                  
          <property name="hibernateProperties">
                      
          <props>
                          
          <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                          
          <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                          
          <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                          
          <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
                          
          </prop>
                          
          <prop key="hibernate.cache.provider_configuration_file_resource_path">${hibernate.ehcache_config_file}</prop>
                      
          </props>
                  
          </property>
                  
          <property name="packagesToScan" value="cn.puretext.entity.*" />
              
          </bean>
              
          <bean id="sessionFactoryIndex" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
                  
          <property name="dataSource" ref="dataSourceIndex" />
                  
          <property name="namingStrategy">
                      
          <bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
                  
          </property>
                  
          <property name="hibernateProperties">
                      
          <props>
                          
          <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                          
          <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                          
          <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                          
          <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
                          
          </prop>
                          
          <prop key="hibernate.cache.provider_configuration_file_resource_path">${hibernate.ehcache_config_file}</prop>
                      
          </props>
                  
          </property>
                  
          <property name="packagesToScan" value="cn.puretext.entity.*" />
              
          </bean>

              
          <!-- 事務(wù)管理器配置,單數(shù)據(jù)源事務(wù) -->
              
          <bean id="transactionManagerContent" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                  
          <property name="sessionFactory" ref="sessionFactoryContent" />
              
          </bean>
              
          <bean id="transactionManagerIndex" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                  
          <property name="sessionFactory" ref="sessionFactoryIndex" />
              
          </bean>

              
          <!-- 事務(wù)管理器配置,多數(shù)據(jù)源JTA事務(wù)-->
              
          <!--
                  <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager or
                  WebLogicJtaTransactionManager" />
              
          -->

              
          <!-- 使用annotation定義事務(wù) -->
              
          <tx:annotation-driven transaction-manager="transactionManagerContent" />
          </beans>

          這個(gè)時(shí)候運(yùn)行還是會(huì)出錯(cuò),出錯(cuò)的原因?yàn)閛rg.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'transactionManager' is defined,因?yàn)樵摮鲥e(cuò)信息很短,我也難以找出究竟是哪個(gè)地方需要名為“transactionManager”的事務(wù)管理器 ,改個(gè)名字都不行,看來Spring的自動(dòng)注入有時(shí)候也錯(cuò)綜復(fù)雜害人不淺。不過,如果把上面的其中一個(gè)名字改成“transactionManger”,另外一個(gè)名字不改,運(yùn)行是成功的,如下:
          <!-- 事務(wù)管理器配置,單數(shù)據(jù)源事務(wù) -->
              
          <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                  
          <property name="sessionFactory" ref="sessionFactoryContent" />
              
          </bean>
              
          <bean id="transactionManagerIndex" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                  
          <property name="sessionFactory" ref="sessionFactoryIndex" />
              
          </bean>

          這個(gè)時(shí)候得出結(jié)論是,可以配置多個(gè)TransactionManager,但是必須有一個(gè)的名字是transactionManager。

          第四步、配置多個(gè)<tx:annotation-driven/>,如下:
              <!-- 使用annotation定義事務(wù) -->
              
          <tx:annotation-driven transaction-manager="transactionManager" />
              
          <tx:annotation-driven transaction-manager="transactionManagerIndex" />

          運(yùn)行測(cè)試,天啦,竟然成功了。和我之前預(yù)料的完全不一樣,居然在一個(gè)配置文件中配置多個(gè)<tx:annotation-driven/>一點(diǎn)問題都沒有。那么在使用@Transactional的地方,它真的能夠選擇正確的事務(wù)管理器嗎?我不得不寫更多的代碼來進(jìn)行測(cè)試。那就針對(duì)索引數(shù)據(jù)庫中的表寫一個(gè)Entity,寫一個(gè)Dao測(cè)試一下吧。

          代碼如下:
          package cn.puretext.entity.web;

          import javax.persistence.Column;
          import javax.persistence.Entity;
          import javax.persistence.Table;

          import org.hibernate.annotations.Cache;
          import org.hibernate.annotations.CacheConcurrencyStrategy;

          import cn.puretext.entity.IdEntity;

          @Entity
          // 表名與類名不相同時(shí)重新定義表名.
          @Table(name = "articles")
          // 默認(rèn)的緩存策略.
          @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
          public class ArticleIndex extends IdEntity {
              
          private String subject;
              
          private String webServer;

              
          public String getSubject() {
                  
          return subject;
              }

              
          public void setSubject(String subject) {
                  
          this.subject = subject;
              }
              @Column(name 
          = "webserver")
              
          public String getWebServer() {
                  
          return webServer;
              }

              
          public void setWebServer(String webServer) {
                  
          this.webServer = webServer;
              }
          }

          package cn.puretext.dao;

          import javax.annotation.Resource;

          import org.hibernate.SessionFactory;
          import org.springframework.stereotype.Repository;
          import org.springside.modules.orm.hibernate.HibernateDao;

          import cn.puretext.entity.web.ArticleIndex;

          @Repository
          public class ArticleIndexDao extends HibernateDao<ArticleIndex, Long> {
              @Override
              @Resource(name 
          = "sessionFactoryIndex")
              
          public void setSessionFactory(SessionFactory sessionFactory) {
                  
          // TODO Auto-generated method stub
                  super.setSessionFactory(sessionFactory);
              }

          }

           

          package cn.puretext.unit.service;

          import java.util.List;

          import javax.annotation.Resource;
          import javax.sql.DataSource;

          import org.junit.Test;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.transaction.annotation.Transactional;
          import org.springside.modules.orm.Page;
          import org.springside.modules.test.junit4.SpringTxTestCase;

          import cn.puretext.dao.ArticleDao;
          import cn.puretext.dao.ArticleIndexDao;
          import cn.puretext.entity.web.Article;
          import cn.puretext.entity.web.ArticleIndex;
          import cn.puretext.service.ServiceException;

          public class DaoTest extends SpringTxTestCase {
              @Autowired
              
          private ArticleDao articleDao;
              @Autowired
              
          private ArticleIndexDao articleIndexDao;
              
              
          public void setArticleIndexDao(ArticleIndexDao articleIndexDao) {
                  
          this.articleIndexDao = articleIndexDao;
              }

              
          public void setArticleDao(ArticleDao articleDao) {
                  
          this.articleDao = articleDao;
              }

              @Override
              @Resource(name 
          = "dataSourceContent")
              
          public void setDataSource(DataSource dataSource) {
                  
          // TODO Auto-generated method stub
                  super.setDataSource(dataSource);
              }

              @Test
              @Transactional
              
          public void addArticle() {
                  Article article 
          = new Article();
                  article.setSubject(
          "article test");
                  article.setContent(
          "article test");
                  articleDao.save(article);
              }

              @Test
              @Transactional
              
          public void pageQuery() {
                  Page
          <Article> page = new Page<Article>();
                  page.setPageSize(
          10);
                  page.setPageNo(
          2);
                  page 
          = articleDao.getAll(page);
                  List
          <Article> articles = page.getResult();
              }
              
              @Test
              @Transactional
              
          public void addIndex() {
                  ArticleIndex articleIndex 
          = new ArticleIndex();
                  articleIndex.setSubject(
          "test");
                  articleIndex.setWebServer(
          "www001");
                  articleIndexDao.save(articleIndex);
              }
              
              @Test
              @Transactional
              
          public void addArticleAndAddIndex() {
                  addArticle();
                  addIndex();
                  
          throw new ServiceException("測(cè)試事務(wù)回滾");
              }
          }


          運(yùn)行測(cè)試,結(jié)果還是成功的。到目前,發(fā)現(xiàn)在一個(gè)項(xiàng)目中使用多個(gè)TransactionManager可以正常運(yùn)行,但是有兩個(gè)問題需要考慮:
          1、為什么必須得有一個(gè)TransactionManager名字為transactionManager?
          2、這兩個(gè)TransactionManager真的能正常工作嗎?
          3、OpenSessionInView的問題怎么解決?

          以上的三個(gè)問題在單元測(cè)試中是不能找出答案的,我只好再去寫Action層的代碼,期望能夠從中得到線索。經(jīng)過一天艱苦的努力,終于真相大白:
          1、并不是必須有一個(gè)TransactionManager的名字為transactionMananger,這只是單元測(cè)試在搞鬼,在真實(shí)的Web環(huán)境中,無論兩個(gè)TransactionManager取什么名字都可以,運(yùn)行不會(huì)報(bào)錯(cuò)。所以這個(gè)答案很明確,是因?yàn)閱卧獪y(cè)試的基類需要一個(gè)名為transactionMananger的事務(wù)管理器。
          2、在單元測(cè)試中,只能測(cè)試Dao類和Entity類能否正常工作,但是由于單元測(cè)試結(jié)束后事務(wù)會(huì)自動(dòng)回滾,不會(huì)把數(shù)據(jù)寫入到數(shù)據(jù)庫中,所以沒有辦法確定兩個(gè)TransactionManager能否正常工作。在真實(shí)的Web環(huán)境中,問題很快就浮出水面,只有一個(gè)數(shù)據(jù)庫中有數(shù)據(jù),另外一個(gè)數(shù)據(jù)庫中沒有,經(jīng)過調(diào)整<tx:annotation-driven/>的位置并對(duì)比分析,發(fā)現(xiàn)只有放在前面的TransactionMananger的事務(wù)能夠正常提交,放在后面的TransactionManager的事務(wù)不能提交,所以永遠(yuǎn)只有一個(gè)數(shù)據(jù)庫里面有數(shù)據(jù)。
          3、如果早一點(diǎn)脫離單元測(cè)試而進(jìn)入真實(shí)的Web環(huán)境,就會(huì)早一點(diǎn)發(fā)現(xiàn)OpenSessionInViewFilter的問題,因?yàn)橹灰渲枚鄠€(gè)SessionFactory,運(yùn)行的時(shí)候OpenSessionInViewFilter就會(huì)報(bào)錯(cuò)。為了解決這個(gè)問題,我只能去閱讀OpenSessionInViewFilter的源代碼,發(fā)現(xiàn)它在將Session綁定到線程的時(shí)候用的是Map,而且使用SessionFactory作為Map的key,這就說明在線程中綁定多個(gè)Session不會(huì)沖突,也進(jìn)一步說明可以在web.xml中配置多個(gè)OpenSessionInViewFilter。而我也正是通過配置多個(gè)OpenSessionInViewFilter來解決問題的。我的web.xml文件如下:

          <?xml version="1.0" encoding="UTF-8"?>
          <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation
          ="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

              
          <display-name>PureText</display-name>
              
          <!-- Spring ApplicationContext配置文件的路徑,可使用通配符,多個(gè)路徑用,號(hào)分隔
                  此參數(shù)用于后面的Spring Context Loader 
          -->
              
          <context-param>
                  
          <param-name>contextConfigLocation</param-name>
                  
          <param-value>classpath*:/applicationContext*.xml</param-value>
              
          </context-param>

              
          <!-- Character Encoding filter -->
              
          <filter>
                  
          <filter-name>encodingFilter</filter-name>
                  
          <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
                  
          <init-param>
                      
          <param-name>encoding</param-name>
                      
          <param-value>UTF-8</param-value>
                  
          </init-param>
                  
          <init-param>
                      
          <param-name>forceEncoding</param-name>
                      
          <param-value>true</param-value>
                  
          </init-param>
              
          </filter>

              
          <filter>
                  
          <filter-name>hibernateOpenSessionInViewFilterContent</filter-name>
                  
          <filter-class>org.springside.modules.orm.hibernate.OpenSessionInViewFilter</filter-class>
                  
          <init-param>
                      
          <param-name>excludeSuffixs</param-name>
                      
          <param-value>js,css,jpg,gif</param-value>
                  
          </init-param>
                  
          <init-param>      
                         
          <param-name>sessionFactoryBeanName</param-name>
                      
          <param-value>sessionFactoryContent</param-value>   
                  
          </init-param>    
              
          </filter>
              
          <filter>
                  
          <filter-name>hibernateOpenSessionInViewFilterIndex</filter-name>
                  
          <filter-class>org.springside.modules.orm.hibernate.OpenSessionInViewFilter</filter-class>
                  
          <init-param>
                      
          <param-name>excludeSuffixs</param-name>
                      
          <param-value>js,css,jpg,gif</param-value>
                  
          </init-param>
                  
          <init-param>      
                         
          <param-name>sessionFactoryBeanName</param-name>
                      
          <param-value>sessionFactoryIndex</param-value>   
                  
          </init-param>    
              
          </filter>
              
          <!-- SpringSecurity filter-->
              
          <filter>
                  
          <filter-name>springSecurityFilterChain</filter-name>
                  
          <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
              
          </filter>

              
          <!-- Struts2 filter -->
              
          <filter>
                  
          <filter-name>struts2Filter</filter-name>
                  
          <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
              
          </filter>

              
          <filter-mapping>
                  
          <filter-name>encodingFilter</filter-name>
                  
          <url-pattern>/*</url-pattern>
              
          </filter-mapping>


              
          <filter-mapping>
                  
          <filter-name>springSecurityFilterChain</filter-name>
                  
          <url-pattern>/*</url-pattern>
              
          </filter-mapping>
              
          <filter-mapping>
                  
          <filter-name>hibernateOpenSessionInViewFilterContent</filter-name>
                  
          <url-pattern>/*</url-pattern>
              
          </filter-mapping>
              
          <filter-mapping>
                  
          <filter-name>hibernateOpenSessionInViewFilterIndex</filter-name>
                  
          <url-pattern>/*</url-pattern>
              
          </filter-mapping>
              
          <filter-mapping>
                  
          <filter-name>struts2Filter</filter-name>
                  
          <url-pattern>/*</url-pattern>
              
          </filter-mapping>

              
          <!--Spring的ApplicationContext 載入 -->
              
          <listener>
                  
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
              
          </listener>

              
          <!-- Spring 刷新Introspector防止內(nèi)存泄露 -->
              
          <listener>
                  
          <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
              
          </listener>

              
          <!-- session超時(shí)定義,單位為分鐘 -->
              
          <session-config>
                  
          <session-timeout>20</session-timeout>
              
          </session-config>

              
          <!-- 出錯(cuò)頁面定義 -->
              
          <error-page>
                  
          <exception-type>java.lang.Throwable</exception-type>
                  
          <location>/common/500.jsp</location>
              
          </error-page>
              
          <error-page>
                  
          <error-code>500</error-code>
                  
          <location>/common/500.jsp</location>
              
          </error-page>
              
          <error-page>
                  
          <error-code>404</error-code>
                  
          <location>/common/404.jsp</location>
              
          </error-page>
              
          <error-page>
                  
          <error-code>403</error-code>
                  
          <location>/common/403.jsp</location>
              
          </error-page>
          </web-app>

          經(jīng)過上面的分析,發(fā)現(xiàn)使用多個(gè)TransactionManager是不可行的(這個(gè)時(shí)候我在想,也許不使用Annotation就可以使用多個(gè)TransactionMananger吧,畢竟Spring的AOP應(yīng)該是可以把不同的TransactionManager插入到不同的類和方法中,但是誰愿意走回頭路呢?畢竟都已經(jīng)是@Transactional的年代了),雖然運(yùn)行不會(huì)報(bào)錯(cuò),但是只有一個(gè)TransactionManager的事務(wù)能夠正常提交。所以測(cè)試進(jìn)入下一步:

          第五步、使用JTATransactionManager

          簡(jiǎn)單地修改配置文件,使用JTATransactionManager做為事務(wù)管理器,配置文件我就不列出來了,運(yùn)行,結(jié)果抱錯(cuò),錯(cuò)誤信息如下:
          org.springframework.beans.factory.BeanCreationException: Error creating bean with name '_filterChainProxy': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '_filterChainList': Cannot create inner bean '(inner bean)' of type [org.springframework.security.config.OrderedFilterBeanDefinitionDecorator$OrderedFilterDecorator] while setting bean property 'filters' with key [10]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)': Cannot resolve reference to bean 'filterSecurityInterceptor' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'filterSecurityInterceptor' defined in file [D:\Temp\1-PureText\WEB-INF\classes\applicationContext-security.xml]: Cannot resolve reference to bean 'databaseDefinitionSource' while setting bean property 'objectDefinitionSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'databaseDefinitionSource': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.interceptor.TransactionInterceptor#0': Cannot resolve reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in file [D:\Temp\1-PureText\WEB-INF\classes\applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: No JTA UserTransaction available - specify either 'userTransaction' or 'userTransactionName' or 'transactionManager' or 'transactionManagerName'

          通過分析,發(fā)現(xiàn)其中最關(guān)鍵的一句是No JTA UserTransaction available,看來,我們只能進(jìn)入到第六步,使用GlassFish了。

          第六步、將項(xiàng)目部署到GlassFish中

          將項(xiàng)目簡(jiǎn)單地部署到GlassFish中之后,項(xiàng)目可以成功運(yùn)行,沒有報(bào)錯(cuò),說明JTA UserTransaction問題解決了,但是檢查數(shù)據(jù)庫卻發(fā)現(xiàn)依然沒有數(shù)據(jù),看來JTATransactionManager不僅要和應(yīng)用服務(wù)器配合使用,還要和JNDI數(shù)據(jù)源一起使用。將數(shù)據(jù)源的配置修改為JNDI后,問題解決。下面是我的配置文件:

          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:jee
          ="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
              xmlns:context
          ="http://www.springframework.org/schema/context"
              xsi:schemaLocation
          ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
              default-lazy-init
          ="true">

              
          <description>Spring公共配置文件 </description>

              
          <!-- 定義受環(huán)境影響易變的變量 -->
              
          <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                  
          <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
                  
          <property name="ignoreResourceNotFound" value="true" />
                  
          <property name="locations">
                      
          <list>
                          
          <!-- 標(biāo)準(zhǔn)配置 -->
                          
          <value>classpath*:/application.properties</value>
                          
          <!-- 本地開發(fā)環(huán)境配置 -->
                          
          <value>classpath*:/application.local.properties</value>
                          
          <!-- 服務(wù)器生產(chǎn)環(huán)境配置 -->
                          
          <!-- <value>file:/var/myapp/application.server.properties</value> -->
                      
          </list>
                  
          </property>
              
          </bean>

              
          <!-- 使用annotation 自動(dòng)注冊(cè)bean,并保證@Required,@Autowired的屬性被注入 -->
              
          <context:component-scan base-package="cn.puretext" />

              
          <!-- 數(shù)據(jù)源配置,使用應(yīng)用服務(wù)器的數(shù)據(jù)庫連接池 -->
              
          <jee:jndi-lookup id="dataSourceContent" jndi-name="jdbc/dataSourceContent" />
              
          <jee:jndi-lookup id="dataSourceIndex" jndi-name="jdbc/dataSourceIndex" />

              
          <!-- Hibernate配置 -->
              
          <bean id="sessionFactoryContent" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
                  
          <property name="dataSource" ref="dataSourceContent" />
                  
          <property name="namingStrategy">
                      
          <bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
                  
          </property>
                  
          <property name="hibernateProperties">
                      
          <props>
                          
          <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                          
          <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                          
          <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                          
          <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
                          
          </prop>
                          
          <prop key="hibernate.cache.provider_configuration_file_resource_path">${hibernate.ehcache_config_file}</prop>
                      
          </props>
                  
          </property>
                  
          <property name="packagesToScan" value="cn.puretext.entity.*" />
              
          </bean>
              
          <bean id="sessionFactoryIndex" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
                  
          <property name="dataSource" ref="dataSourceIndex" />
                  
          <property name="namingStrategy">
                      
          <bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
                  
          </property>
                  
          <property name="hibernateProperties">
                      
          <props>
                          
          <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                          
          <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                          
          <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                          
          <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
                          
          </prop>
                          
          <prop key="hibernate.cache.provider_configuration_file_resource_path">${hibernate.ehcache_config_file}</prop>
                      
          </props>
                  
          </property>
                  
          <property name="packagesToScan" value="cn.puretext.entity.*" />
              
          </bean>

              
          <!-- 事務(wù)管理器配置,單數(shù)據(jù)源事務(wù) -->
              
          <!--
              <bean id="transactionManagerContent" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                  <property name="sessionFactory" ref="sessionFactoryContent" />
              </bean>
              <bean id="transactionManagerIndex" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                  <property name="sessionFactory" ref="sessionFactoryIndex" />
              </bean>
              
          -->
              
              
          <!-- 事務(wù)管理器配置,多數(shù)據(jù)源JTA事務(wù)-->
              
              
          <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
              

              
          <!-- 使用annotation定義事務(wù) -->
              
          <tx:annotation-driven transaction-manager="transactionManager" />
              
          </beans>

          最后,我得出的結(jié)論是:要想使用多個(gè)數(shù)據(jù)庫,就必須使用JTATransactionMananger,必須使用GlassFish等應(yīng)用服務(wù)器而不是Tomcat,必須使用JNDI來管理dataSource。

          如果一定要使用Tomcat呢?

          這確實(shí)是一個(gè)難題,但是并不代表著沒有解決辦法。經(jīng)過廣泛的Google一番之后,終于發(fā)現(xiàn)了一個(gè)好東東,那就是JOTM,它的全稱就是Java Open Transaction Mananger,它的作用就是可以單獨(dú)提供JTA事務(wù)管理的功能,不需要應(yīng)用服務(wù)器。JOTM的使用方法有兩種,一種就是把它配置到項(xiàng)目中,和Spring結(jié)合起來使用,另外一種就是把它配置到Tomcat中,這時(shí),Tomcat搖身一變就成了和GlassFish一樣的能夠提供JTA功能的服務(wù)器了。

          JOTM的官方網(wǎng)站為http://jotm.ow2.org,這是它的新網(wǎng)站,舊網(wǎng)站為http://jotm.objectweb.org

          我選擇了把JOTM 2.0.11整合到Tomcat中的方法進(jìn)行了測(cè)試,結(jié)果發(fā)現(xiàn)還是不能夠正常運(yùn)行,我使用的是JOTM2.0.11,Tomcat 6.0.20,JKD 6 Update10。看來還得繼續(xù)折騰下去了。

          另外一個(gè)開源的JTA事務(wù)管理器是Atomikos,它供了事務(wù)管理和連接池,不需要應(yīng)用服務(wù)器支持,其官方網(wǎng)站為http://www.atomikos.com/。有興趣的朋友可以試試。


          評(píng)論

          # re: SpringSide 3 中的多數(shù)據(jù)源配置  回復(fù)  更多評(píng)論   

          2009-07-13 22:03 by 虎嘯龍吟
          能搞定?還沒看明白

          # re: SpringSide 3 中的多數(shù)據(jù)源配置  回復(fù)  更多評(píng)論   

          2009-07-14 14:47 by lsqlister
          寫的很好。
          問題1:spring中默認(rèn)不是要配一個(gè)transactionManager嗎?

          # re: SpringSide 3 中的多數(shù)據(jù)源配置的問題  回復(fù)  更多評(píng)論   

          2009-07-24 22:40 by 虎嘯龍吟
          到底tomcat能不能支持多數(shù)據(jù)源實(shí)現(xiàn)啊?

          # re: SpringSide 3 中的多數(shù)據(jù)源配置的問題  回復(fù)  更多評(píng)論   

          2009-07-25 12:56 by 海邊沫沫
          單獨(dú)的Tomcat不行

          加上Atomikos就可以。

          # re: SpringSide 3 中的多數(shù)據(jù)源配置的問題  回復(fù)  更多評(píng)論   

          2009-07-26 10:32 by 虎嘯龍吟
          明白了

          # re: SpringSide 3 中的多數(shù)據(jù)源配置的問題  回復(fù)  更多評(píng)論   

          2009-12-14 13:16 by 夫子一品
          樓主專研的精神不錯(cuò),值得學(xué)習(xí)!

          # re: SpringSide 3 中的多數(shù)據(jù)源配置的問題[未登錄]  回復(fù)  更多評(píng)論   

          2009-12-22 17:52 by Harry
          樓主太好了,給我了很多思路

          # re: SpringSide 3 中的多數(shù)據(jù)源配置的問題[未登錄]  回復(fù)  更多評(píng)論   

          2010-08-03 13:09 by Aaronlong31
          我之前使用iBATIS+spring+Atomikos成功過。

          # re: SpringSide 3 中的多數(shù)據(jù)源配置的問題  回復(fù)  更多評(píng)論   

          2011-05-17 15:52 by 省時(shí)
          tomcat下 Error creating bean with name '_filterChainProxy': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '_filterChainList': Cannot create inner bean '(inner bean)' of type 這個(gè)問題解決沒?

          # re: SpringSide 3 中的多數(shù)據(jù)源配置的問題[未登錄]  回復(fù)  更多評(píng)論   

          2011-12-09 17:22 by hot
          但是好像spring3.0(具體版本沒弄清)之前的Transactional標(biāo)注不支持區(qū)分使用哪個(gè)事務(wù)管理器。3.0之后的版本Transactional增加了個(gè)string類型的value屬性來特殊指定加以區(qū)分。

          # re: SpringSide 3 中的多數(shù)據(jù)源配置的問題[未登錄]  回復(fù)  更多評(píng)論   

          2011-12-09 17:24 by hot
          如果調(diào)換兩個(gè)事務(wù)管理器在容器中的定義順序,如
          <tx:annotation-driven transaction-manager="transactionManagerY" />
          <tx:annotation-driven transaction-manager="transactionManagerX" />
          得到的結(jié)果
          methodX()事務(wù)生效測(cè)試結(jié)果 @Transactional
          ("transactionManagerX")
          @Transactional
          ("transactionManagerY")
          @Transactional
          ("transactionManagerZ")
          transactionManagerZ為未定義過的 @Transactional
          TestEntityServiceImpl(實(shí)際使用datasourceX) Y N N N
          AnotherTestEntityServiceImpl (實(shí)際使用datasourceY) N Y Y Y


          分析結(jié)果(其實(shí)源碼就可以反應(yīng)出):容器指定一個(gè)默認(rèn)的事務(wù)管理器
          1.當(dāng)在@Transactional("xxx")中正確指定了需要使用的事務(wù)管理器時(shí),事務(wù)控制正常。
          2.如果@Transactional指定了未定義過的事務(wù)管理器,spring以缺省默認(rèn)的事務(wù)管理器來處理。(如果程序正好使用的是缺省事務(wù)管理器同一個(gè)數(shù)據(jù)源,事務(wù)控制將生效)。
          3.如果@Transactional不指定事務(wù)管理器,使用缺省。
          4.如果@Transactional指定了不匹配的事務(wù)管理器(實(shí)際用到的數(shù)據(jù)源和指定的事務(wù)管理器控制的數(shù)據(jù)源不一致),事務(wù)控制將失效.
          主站蜘蛛池模板: 正安县| 锦州市| 大荔县| 麻城市| 封丘县| 淄博市| 正定县| 万盛区| 武强县| 阿鲁科尔沁旗| 化德县| 龙海市| 思南县| 泸定县| 新疆| 普兰店市| 泗水县| 南召县| 奉化市| 鄂伦春自治旗| 盐池县| 丽江市| 封丘县| 宁晋县| 南开区| 津市市| 文水县| 游戏| 宁安市| 且末县| 漠河县| 祁阳县| 绥江县| 体育| 高邮市| 无为县| 云南省| 贵定县| 镇雄县| 乐至县| 新竹市|