一、采用读写分离技术的目标

随着网站的业务不断扩展,数据不断增加,用户越来越多,数据库的压力也就越来越大,采用传统的方式,比如:数据库或者SQL的优化基本已达不到要求,这个时候可以采用读写分离的策略来改变现状。采用读写分离技术能够有效减轻Master库的压力,又可以把用户查询数据的请求分发到不同的Slave库,从而保证系统的健壮性。

二、常用的两种方式

1、定义两个数据库链接,一个是masterDataSource,另个是slaveDataSource,更新数据时读取masterDataSource,查询是读取slaveDataSource。

2、动态数据源切换,在程序运行时,把数据源动态织如入程序中,从而选择主库还是从库。主要技术采用annotation,Spring AOP,反射,接下来详细介绍该种方法。

三、动态数据源切换实现读写分离

1,定义DataSource注解

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface DataSource {

String value();

}

2,继承抽象类AbstractRoutingDataSource来实现DynamicDataSource方法

public class DynamicDataSource extends AbstractRoutingDataSource{

public static final Logger logger = Logger.getLogger(DynamicDataSource.class.toString());

@Override

protected Object determineCurrentLookupKey() {

return DynamicDataSourceHolder.getDataSource();

}

}

3,定义DynamicDataSourceHolder方法

public class DynamicDataSourceHolder {

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

public static void setDataSource(String name) {

holder.set(name);

}

public static String getDataSource() {

return holder.get();

}

}

4,定义DataSourceAspect类,在程序运行时动态切换数据源

public class DataSourceAspect {

public void before(JoinPoint point){

Object target = point.getTarget();

String method = point.getSignature().getName();

Class<?>[] classz = target.getClass().getInterfaces();

Class<?>[] parameterTypes = ((MethodSignature)point.getSignature()).getParameterTypes();

try{

Method m = classz[0].getMethod(method, parameterTypes);

if(m != null && m.isAnnotationPresent(DataSource.class)){

DataSource date = m.getAnnotation(DataSource.class);

DynamicDataSourceHolder.setDataSource(date.value());

}

else {

// 默认master

DynamicDataSourceHolder.setDataSource("master");

}

}catch(Exception e){

}

}

}

5,applicationContext-dataSource.xml配置

分别定义主从数据源后,再添加选择数据源的bean

<bean id="dataSource" class="****">

<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>

增加aop配置

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>      <bean id="manyDataSourceAspect" class="****.DataSourceAspect" />

<aop:config>

<aop:aspect id="c" ref="manyDataSourceAspect">

<aop:before method="before" pointcut="execution(* *****.data.dao.*.*(..))"></aop:before>

</aop:aspect>

</aop:config>

6,DAO层定义方法的数据源

@DataSource(value="slave")

public ImUser findById(int id);

05-11 19:46