现在的位置: 首页 > 综合 > 正文

Spring动态数据源路由实现

2014年01月31日 ⁄ 综合 ⁄ 共 4625字 ⁄ 字号 评论关闭

简单的翻译, 也算是一篇笔记. 

原文:http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/ 

在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上, 同时对于不支持事务隔离级别的JTA事务来说, Spring还提供了另外一个类IsolationLevelDataSourceRouter来处理这个问题. 下面的例子将通过context来切换不同的数据源. 

首先定义一个Catalog的Dao: 

Java代码  

 package blog.datasource;  

  

import java.sql.ResultSet;  

import java.sql.SQLException;  

import java.util.List;  

  

import org.springframework.jdbc.core.simple.ParameterizedRowMapper;  

import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;  

  

public class Catalog extends SimpleJdbcDaoSupport {  

          

   public List<Item> getItems() {  

      String query = "select name, price from item";  

      return getSimpleJdbcTemplate().query(query, new ParameterizedRowMapper<Item>() {  

            public Item mapRow(ResultSet rs, int row) throws SQLException {  

               String name = rs.getString(1);  

               double price = rs.getDouble(2);  

               return new Item(name, price);  

            }  

      });  

   }  

}  

 

 

然后定义一个Item的JavaBean 

Java代码  

package blog.datasource;  

  

public class Item {  

  

   private String name;  

   private double price;  

          

   public Item(String name, double price) {  

      this.name = name;  

      this.price = price;  

   }  

  

   public String getName() {  

      return name;  

   }  

  

   public double getPrice() {  

      return price;  

   }  

  

   public String toString() {  

      return name + " (" + price + ")";  

   }  

  

}  

 

 

接着定义一个枚举类型, 用来表示不同的用户级别, 通过该类型将映射到不同的数据源 

Java代码  

public enum CustomerType {  

   BRONZE,   

   SILVER,   

   GOLD  

}  

 

 

下面是DataSource定义: 

Xml代码  

<bean id="parentDataSource"  

         class="org.springframework.jdbc.datasource.DriverManagerDataSource"  

         abstract="true">  

   <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>  

   <property name="username" value="sa"/>  

</bean>  

                  

<bean id="goldDataSource" parent="parentDataSource">  

   <property name="url" value="jdbc:hsqldb:hsql://localhost:${db.port.gold}/blog"/>  

</bean>  

  

<bean id="silverDataSource" parent="parentDataSource">  

   <property name="url" value="jdbc:hsqldb:hsql://localhost:${db.port.silver}/blog"/>  

</bean>  

  

<bean id="bronzeDataSource" parent="parentDataSource">  

   <property name="url" value="jdbc:hsqldb:hsql://localhost:${db.port.bronze}/blog"/>  

</bean>  

  

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  

   <property name="location" value="classpath:/blog/datasource/db.properties"/>  

</bean>  

 

 

AbstractRoutingDataSource 实现类 

Java代码  

package blog.datasource;  

  

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  

  

public class CustomerRoutingDataSource extends AbstractRoutingDataSource {  

  

   @Override  

   protected Object determineCurrentLookupKey() {  

      return CustomerContextHolder.getCustomerType();  

   }  

}  

 

 

CustomerContextHolder 是一个和LocalThread绑定的类, 定义如下: 

Java代码  

public class CustomerContextHolder {  

  

   private static final ThreadLocal<CustomerType> contextHolder =   

            new ThreadLocal<CustomerType>();  

          

   public static void setCustomerType(CustomerType customerType) {  

      Assert.notNull(customerType, "customerType cannot be null");  

      contextHolder.set(customerType);  

   }  

  

   public static CustomerType getCustomerType() {  

      return (CustomerType) contextHolder.get();  

   }  

  

   public static void clearCustomerType() {  

      contextHolder.remove();  

   }  

}  

 

 

将dao bean和datasource bean结合起来, 至于dao和真正的datasource如何关联这个可以根据需要指定相关的策略和规则来实现: 

Xml代码  

<bean id="catalog" class="blog.datasource.Catalog">  

   <property name="dataSource" ref="dataSource"/>  

</bean>  

  

<bean id="dataSource" class="blog.datasource.CustomerRoutingDataSource">  

   <property name="targetDataSources">  

      <map key-type="blog.datasource.CustomerType">  

         <entry key="GOLD" value-ref="goldDataSource"/>  

         <entry key="SILVER" value-ref="silverDataSource"/>  

      </map>  

   </property>  

   <property name="defaultTargetDataSource" ref="bronzeDataSource"/>  

</bean>  

 

下面通过一个TestCase来看看如何使用: 

Java代码  

public class CatalogTests extends AbstractDependencyInjectionSpringContextTests {  

  

   private Catalog catalog;  

  

   public void setCatalog(Catalog catalog) {  

      this.catalog = catalog;  

   }  

  

   public void testDataSourceRouting() {  

      CustomerContextHolder.setCustomerType(CustomerType.GOLD);  

      List<Item> goldItems = catalog.getItems();  

      assertEquals(3, goldItems.size());  

      System.out.println("gold items: " + goldItems);  

  

      CustomerContextHolder.setCustomerType(CustomerType.SILVER);  

      List<Item> silverItems = catalog.getItems();  

      assertEquals(2, silverItems.size());  

      System.out.println("silver items: " + silverItems);  

          

      CustomerContextHolder.clearCustomerType();  

      List<Item> bronzeItems = catalog.getItems();  

      assertEquals(1, bronzeItems.size());  

      System.out.println("bronze items: " + bronzeItems);                

   }  

  

   protected String[] getConfigLocations() {  

      return new String[] {"/blog/datasource/beans.xml"};  

   }      

}  

抱歉!评论已关闭.