使用Spring实现多数据源操作

Spring提供了抽象类AbstractRoutingDataSource,允许动态设置数据源,从而实现对多数据源进行数据读写操作。

 

1、首先需要定义一个类继承抽象类AbstractRoutingDataSource,并实现相应的方法determineCurrentLookupKey:

protected Object determineCurrentLookupKey() { }

决定使用哪个LookupKey作为目前的数据源key。

 

2、写一个辅助类,用于实现数据源的选择、切换,由于数据源是多线程共享的,需要确保线程安全,可以使用ThreadLocal来保存每个线程的数据源key。

public class DataSourceSelector{

  private static final ThreadLocal<String> dataSourceHolder = new ThreadLocal<String>();

  public static void setDataSource1() { dataSourceHolder.set(“dataSource1”);  }

  public static void setDataSource2() { dataSourceHolder.set(“dataSource1”);  }

}

3、在spring配置文件中配置多个数据源信息:

    <bean id="dataSource1">

        <property name="driverClass" value="" />

        <property name="jdbcUrl" value="" />

        <property name="user" value="" />

        <property name="password" value="" />

    </bean>

    <bean id="dataSource2">

        <property name="driverClass" value="" />

        <property name="jdbcUrl" value="" />

        <property name="user" value="" />

        <property name="password" value="" />

    </bean>

    <bean id="dataSource" class="com.xx.dao.DynamicDataSource">

        <property name="targetDataSources">

            <map key-type="java.lang.String">

                <entry key="dataSource1" value-ref="dataSource1" />

       <entry key="dataSource2" value-ref="dataSource2" />

            </map>

        </property>

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

    </bean>

DynamicDataSource即为第一步中实现抽象类AbstractRoutingDataSource的具体选择数据源的类。

4、在需要切换数据源的时候,调用DataSourceSelector类的方法设置需要的数据源就可以了。

 

在此基础上,还可以结合spring AOP实现mysql等数据库的读写分离,为此需要定义一个类实现MethodBeforeAdvice,AfterReturningAdvice,ThrowsAdvice,如下:

public class DataSourceAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {

  public void before(Method method, Object[] args, Object target) throws Throwable {

    // 方法执行之前,设置数据源    
    String methodName = method.getName();
      if (methodName.startsWith("get") || method.getName().startsWith("select")) 
          DataSourceSelector.setSlave();
      else
          DataSourceSelector.setMaster();    
  }

  public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { }

  public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {DataSourceSelector.setSlave();}

}

需要在Spring配置文件里增加通知的配置项:

<!-- 切换数据源拦截器,拦截com.xx.dao.impl下的所有类的所有方法 -->
<bean id="dataSourceAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  <property name="advice">
    <bean class="com.xx.dao.dynamic.DataSourceAdvice"/>
  </property>
  <property name="patterns">
    <list>
      <value>.*</value>
    </list>
  </property>
</bean>


<!-- 所有以DaoImpl结尾的bean都拦截以自动选择数据库 -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
  <property name="beanNames" value="*DaoImpl" />
  <property name="interceptorNames">
    <list>
      <value>dataSourceAdvisor</value>
    </list>
  </property>
</bean>

DaoImpl里的所有以get或者select开头的方法都会从slave数据库读取数据,而其他方法,例如以insert、update开头的方法都会往master数据库里存数据,从而实现读写分离。

posted @ 2013-05-27 12:50  7mile  阅读(458)  评论(0编辑  收藏  举报