zoukankan      html  css  js  c++  java
  • Spring实现数据库读写分离

    借助于Spring框架在2.0.1之后提供的AbstractRoutingDataSource可以实现动态的选择数据源datasource,下面先举一个最简单的例子(可以参考这个链接):
     
    1. 首先新建 一个Catalog VO对象的DAO(见代码1),它继承了SimpleJdbcDaoSupport,JdbcDaoSupport需要注入一个DataSource,同 时也提供了操作模板JdbcTemplate。添加一个方法用于获取所有的“货物Item”。货物Iteam是一个POJO类(见代码2)。
     
    代码1:
    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);
                }
          });
       }
    }
     
    代码2:
    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 + ")";
       }
     
    }
     
     
    2. 配置Spring多数据源,这里配置了一个主库和一个从库,他们可以共同继承一个父的数据源。
    代码3:
    <bean id="parentDataSource"
             class="org.springframework.jdbc.datasource.DriverManagerDataSource"
             abstract="true">
       <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
       <property name="username" value="test"/>
    </bean>
     
    <!--  主库 -->
    <bean id="masterDataSource" parent="parentDataSource">
       <property name="url" value="jdbc:mysql://localhost:${db.port.master}/blog"/>
    </bean>
     
    <!--  从库 -->
    <bean id="slaveDataSource" parent="parentDataSource">
       <property name="url" value="jdbc:mysql://localhost:${db.port.slave}/blog"/>
    </bean>
     
    <!-- 用PropertyPlaceholderConfigurer来读取properties配置,此处省略配置 -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
       <property name="location" value="classpath:/blog/datasource/db.properties"/>
    </bean>
     
     
    3. 新建一个 datasource继承自AbstractRoutingDataSource,并且覆盖determineCurrentLookupKey()方 法,每次用这个datasource获取数据库连接的时候都会回调这个方法获得key,根据返回的字符串key(也可以是枚举值,数字类型),动态地通过 datasource配置的id来在Spring的配置文件中找到相应的datasource来获取connection(见代码4)。那么如果每次访问 都需要根据key来决定如何选择数据源,那么这个key必须要保证线程安全,并发情况下每个线程都会去寻找本应该属于自己的key获取数据源,所以 CustomerContextHolder类中就用到了ThreadLocal来保证(见代码5)。
     
    代码4:
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
     
    public class CustomerRoutingDataSource extends AbstractRoutingDataSource {
     
       @Override
       protected Object determineCurrentLookupKey() {
          return CustomerContextHolder.getCustomerType();
       }
    }
     
    代码5:
    public class CustomerContextHolder {
     
       private static final ThreadLocal<String> contextHolder =
                new ThreadLocal<String>();
     
       public static void setCustomerType(String customerType) {
          Assert.notNull(customerType, "customerType cannot be null");
          contextHolder.set(customerType);
       }
     
       public static String getCustomerType() {
          return (String) contextHolder.get();
       }
     
       public static void clearCustomerType() {
          contextHolder.remove();
       }
    }
     
     
    在Spring中的配置如下:
     
    代码6:
    <bean id="catalog" class="blog.datasource.Catalog">
       <property name="dataSource" ref="dataSource"/>
    </bean>
     
    <bean id="dataSource" class="blog.datasource.CustomerRoutingDataSource">
       <!-- 这个targetDataSource是必须要注入的 -->
    <property name="targetDataSources">
          <map key-type="java.lang.String">
             <entry key="MASTER" value-ref="masterDataSource"/>
             <entry key="SLAVE" value-ref="slaveDataSource"/>
          </map>
       </property>
       <!-- 默认的数据源 -->
       <property name="defaultTargetDataSource" ref="masterDataSource"/>
    </bean>
     
     
    4. 测试用例
     
    代码7:
    AbstractDependencyInjectionSpringContextTests {
     
       private Catalog catalog;
     
       public void setCatalog(Catalog catalog) {
          this.catalog = catalog;
       }
     
       public void testDataSourceRouting() {
          CustomerContextHolder.setCustomerType(“MASTER”);
          List<Item> goldItems = catalog.getItems();
          assertEquals(3, goldItems.size());
          System.out.println("gold items: " + goldItems);
     
          CustomerContextHolder.setCustomerType(“SLAVE”);
          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"};
       }
    }
    5
     
    您可能也喜欢:
  • 相关阅读:
    ASP.NET MVC @helper使用说明
    asp.net批量发布博客到各大博客平台
    大型网站架构学习
    Js获取日期时间及其它操作
    Asp.net 后台添加Meta标签方法
    正则表达式排除特定字符串
    asp.net正则表达式过滤标签和数据提取
    <pages validateRequest="false"/>在.net4.0中无效的问题
    IE6、IE7、IE8中overflow:hidden无效问题
    如何在 Django 中保证并发的数据一致性
  • 原文地址:https://www.cnblogs.com/seasonzone/p/3956363.html
Copyright © 2011-2022 走看看