于吉吉的技術博客

          建造高性能門戶網

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            65 隨筆 :: 6 文章 :: 149 評論 :: 0 Trackbacks
          前段時間我們的系統接到新增多一個頻道的需求,原本我們的系統只是針對于廣州的業務,現在需要新增另一個城市上海,經過和產品人員溝通和分析,城市之間的業務邏輯除了一些小差異基本還是一樣的,數據庫的結構經過整合兩個城市也可以達到一樣的結構,但上海需要獨立出另一個數據庫.

          我們以前發布器的做法是用作為方法的一個參數由調用者一直傳到訪問對象(索引或數據庫),雖然這種做法一樣可以很快的實現,但是將數據庫,索引的選擇和業務邏輯混搭在一起的設計在感覺上是比較混亂,并且不利于將來多個城市(頻道)的建立,所以選了通過ThreadLocal來實現多數據源的動態切換.

          ThreadLocal 是一個依賴于執行線程的存儲器,對它就只有簡單的一個set和get方法,不同線程之間是相互獨立的。簡單地講,就是:這個線程set了一個對象入去,只有這個線程自己可以把它get出來,其它線程是get不出來的。

          好了,下面是具體顯示的方式

          首先定義一個filter,通過filter取得域名,因為我們的域名中帶有城市的標志,如廣州是http://gz.***.com,上海是http://sh.***.com,通過取得的域名,我們取得城市的表示放進ThreadLocal.set(city);

          public class DataSourceFilter extends HttpServlet implements Filter {

          public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain filterChain) {
                HttpServletRequest req 
          = (HttpServletRequest) request;
                String servername 
          = req.getServerName();
                SpObserver.putCityByDomain(servername);
                filterChain.doFilter(request, response);
            }

          }

          public class SpObserver {
              
          private static ThreadLocal<String> local = new ThreadLocal<String>();    

              
          public static void putCityByDomain(String domain) {
                  String city 
          = publicconfig.getCityMap().get(domain);//拆分domain,獲取城市名
                  local.set(city);
              }
              
          public static String getCity() {
                  String city 
          = (String) local.get();
                  
          return city;
              }

          }

          建立多個與之對應的數據源


              
          <bean id="atomDataSource_gz"
                  class
          ="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
                  destroy-method
          ="close">
                  
          <property name="uniqueResourceName">
                      
          <value>mysql/gz</value>
                  
          </property>
                  
          <property name="xaDataSourceClassName">
                      
          <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
                  
          </property>
                  
          <property name="xaProperties">
                      
          <props>
                          
          <prop key="URL"><![CDATA[${jdbc_gz.url}]]></prop>
                          
          <prop key="user"><![CDATA[${jdbc_gz.username}]]></prop>
                          
          <prop key="password"><![CDATA[${jdbc_gz.password}]]></prop>
                      
          </props>
                  
          </property>
                  
          <property name="maxPoolSize">
                      
          <value>50</value>
                  
          </property>
                  
          <property name="minPoolSize">
                      
          <value>5</value>
                  
          </property>
                  
          <property name="loginTimeout">
                      
          <value>20</value>
                  
          </property>
                  
          <property name="testQuery">
                      
          <value>SELECT 1</value>
                  
          </property>
              
          </bean>

          <bean id="atomDataSource_sh"
                  class
          ="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
                  destroy-method
          ="close">
                  
          <property name="uniqueResourceName">
                      
          <value>mysql/sh</value>
                  
          </property>
                  
          <property name="xaDataSourceClassName">
                      
          <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
                  
          </property>
                  
          <property name="xaProperties">
                      
          <props>
                          
          <prop key="URL"><![CDATA[${jdbc_sh.url}]]></prop>
                          
          <prop key="user"><![CDATA[${jdbc_sh.username}]]></prop>
                          
          <prop key="password"><![CDATA[${jdbc_sh.password}]]></prop>
                      
          </props>
                  
          </property>
                  
          <property name="maxPoolSize">
                      
          <value>50</value>
                  
          </property>
                  
          <property name="minPoolSize">
                      
          <value>5</value>
                  
          </property>
                  
          <property name="loginTimeout">
                      
          <value>20</value>
                  
          </property>
                  
          <property name="testQuery">
                      
          <value>SELECT 1</value>
                  
          </property>
              
          </bean>

              
          <bean id="dataSource" class="com.***.shine.constant.MultiDataSource">  
                  
          <property name="dataSource" ref="atomDataSource_gz" /> <!-- 默認城市為gz -->
              
          </bean>


          public class MultiDataSource extends AtomikosDataSourceBean implements ApplicationContextAware {
              
          private ApplicationContext applicationContext = null;
              
          private DataSource dataSource = null;
              
          public Connection getConnection() throws SQLException {
                  
          return getDataSource().getConnection();
              }
              
          public Connection getConnection(String arg0, String arg1)
                      
          throws SQLException {
                  
          return getDataSource().getConnection(arg0, arg1);
              }
              ..
              
              
          //通過適配者的設計模式動態的切換實現類,這樣就實現了在DataSourceBean中,我們是要注入atomDataSource_gz還是atomDataSource_sh
              public DataSource getDataSource(String dataSourceName) {
                  
          try{
                      
          if(dataSourceName==null||dataSourceName.equals("")){
                          
          return this.dataSource;
                      }
                      
          return (DataSource)this.applicationContext.getBean(dataSourceName);
                  }
          catch(NoSuchBeanDefinitionException ex){
                      
          throw new DaoException("There is not the dataSource <name:"+dataSourceName+"> in the applicationContext!");
                  }
              }
              
              
          public void setDataSource(DataSource dataSource) {
                  
          this.dataSource = dataSource;
              }
              
          //主要是下面這一段,通過SpObserver.getCity() 獲取相應的城市(頻道)名字
              public DataSource getDataSource(){
                  String city 
          = SpObserver.getCity();
                  
          if(city == null || city.equals(""|| city.equals("null"))
                      city 
          = "gz";
                  
          return getDataSource("atomDataSource_"+city);
              }
              ...
          }

          這樣在各個層中的實現我們就不需去關注究竟是哪個城市的接口,因為每個請求都附帶了ThreadLocal的相應信息

          關于ThreadLocal具體可看-->通通透透理解ThreadLocal

          posted on 2010-08-23 16:22 陳于喆 閱讀(3472) 評論(1)  編輯  收藏 所屬分類: spring

          評論

          # re: 動態切換多數據源的配置[未登錄] 2010-08-24 11:07 Jet
          Spring中有個DataSourceHolder,可以直接拿來用。  回復  更多評論
            


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 克拉玛依市| 读书| 江北区| 竹山县| 云梦县| 镇平县| 三亚市| 闽清县| 从化市| 绥芬河市| 巴林左旗| 奉化市| 石首市| 会同县| 桑植县| 广东省| 临沭县| 杂多县| 新河县| 葫芦岛市| 新民市| 西乡县| 东安县| 平潭县| 乌苏市| 普定县| 准格尔旗| 屏山县| 义马市| 江津市| 石城县| 红原县| 青龙| 建始县| 新密市| 曲松县| 通榆县| 泗洪县| 增城市| 元阳县| 广南县|