使用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数据库里存数据,从而实现读写分离。