Spring实现数据库读写分离

数据库读写分离是最基本的DB扩展方式,我们可以在应用中自己实现,决定什么业务访问写库,什么业务访问读库。
Spring提供了一套机制可以声明式地实现读写分离,简化我们的开发。下面把最主要的几块列出来。
1,AbstractRoutingDataSource,这是Spring提供的最核心的组件,由它来管理所有的写库、读库,并统一对外提供dataSource。
在这里,DynamicDataSource继承了AbstractRoutingDataSource,并在配置中指明了所有的读写库。dynamicDs_galaxy就是统一对外提供的dataSource,
之后,注入DAO、transaction管理,都将使用dynamicDs_galaxy。

点击(此处)折叠或打开

  1. <bean id="dynamicDs_galaxy" class="com.sogou.earth.api.common.db.DynamicDataSource">
  2.         <property name="targetDataSources">
  3.             <map key-type="java.lang.String">
  4.                 <entry key="master" value-ref="ds_galaxy_master" />
  5.                 <entry key="slave" value-ref="ds_galaxy_slave" />
  6.             </map>
  7.         </property>
  8.         <property name="defaultTargetDataSource" ref="ds_galaxy_master" />
  9.     </bean>

在代码里实现determineCurrentLookupKey方法,该方法就一个作用:获取key,以便根据key获取哪个datasource。

点击(此处)折叠或打开

  1. package com.sogou.earth.api.common.db;

  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

  5. public final class DynamicDataSource extends AbstractRoutingDataSource {

  6.     private static final Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);

  7.     protected Object determineCurrentLookupKey() {
  8.         Object object = DynamicDataSourceKeyHolder.getDataSourceKey();
  9.         logger.debug("determineCurrentLookupKey:" + object);
  10.         return object;
  11.     }
  12. }

2,DynamicDataSourceInterceptor,这是个拦截器,最终会以advice的形式拦截所有需要访问DB的业务,它的作用是给需要DB访问的业务分配一个key,
这个key用来 determineCurrentLookupKey,最终确定访问哪个dataSource。

点击(此处)折叠或打开

  1. <bean id="dynamicDsInterceptor_galaxy" class="com.sogou.earth.api.common.db.DynamicDataSourceInterceptor">
  2.         <property name="attributeSource">
  3.             <list>
  4.                 <value>query*,slave</value>
  5.                 <value>count*,slave</value>
  6.                 <value>find*,slave</value>
  7.                 <value>get*,slave</value>
  8.                 <value>list*,slave</value>
  9.                 <value>*,master</value>
  10.             </list>
  11.         </property>
  12.     </bean>

代码:根据业务方法名来分配key。

点击(此处)折叠或打开

  1. package com.sogou.earth.api.common.db;

  2. import java.util.ArrayList;
  3. import java.util.List;

  4. import org.aopalliance.intercept.MethodInterceptor;
  5. import org.aopalliance.intercept.MethodInvocation;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import org.springframework.util.PatternMatchUtils;

  9. /**
  10.  * 设置数据源KEY的拦截器
  11.  *
  12.  */
  13. public class DynamicDataSourceInterceptor implements MethodInterceptor {

  14.     private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceInterceptor.class);
  15.     /**
  16.      * 方法和使用数据源key的对应关系
  17.      */
  18.     private List<String> attributeSource = new ArrayList<String>();

  19.     public Object invoke(MethodInvocation invocation) throws Throwable {
  20.         final String methodName = invocation.getMethod().getName();
  21.         String key = null;
  22.         for (String value : attributeSource) {
  23.             String mappedName = value.split(\",\")[0];
  24.             if (isMatch(methodName, mappedName)) {
  25.                 key = value.split(\",\")[1];
  26.                 break;
  27.             }
  28.         }
  29.         logger.debug(\"methodName:\" + methodName);
  30.         if (null != key) {
  31.             DynamicDataSourceKeyHolder.setKey(key);
  32.         }

  33.         return invocation.proceed();
  34.     }

  35.     private boolean isMatch(String methodName, String mappedName) {
  36.         return PatternMatchUtils.simpleMatch(mappedName, methodName);
  37.     }

  38.     public List<String> getAttributeSource() {
  39.         return attributeSource;
  40.     }

  41.     public void setAttributeSource(List<String> attributeSource) {
  42.         this.attributeSource = attributeSource;
  43.     }

  44. }

DynamicDataSourceKeyHolder里面持有ThreadLocal,是线程安全的。

点击(此处)折叠或打开

  1. package com.sogou.earth.api.common.db;

  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;

  4. public class DynamicDataSourceKeyHolder {

  5.     private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceKeyHolder.class);
  6.     
  7.     private static final ThreadLocal<String> dataSourceHolder = new ThreadLocal<String>();

  8.     public static void setKey(String key) {
  9.         dataSourceHolder.set(key);
  10.     }

  11.     public static String getDataSourceKey() {
  12.         return (String) dataSourceHolder.get();
  13.     }
  14. }

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28912557/viewspace-1577667/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/28912557/viewspace-1577667/

你可能感兴趣的:(Spring实现数据库读写分离)