在项目中,有遇到随业务场景的不同,而切换不同库的操作,本来考虑利用mycat来实现,但后来发现基于mycat本身的适用场景与我们的需求并不符,如果用的话,会有两个问题:
mycat需要单独部署,虽不大,但又增加了现场的docker数,浪费资源;我们的业务并不是基于数据库字段来切库,并且mycat已提供的几种切库方式没有我们的场景,要套用的话,虽可用注解的方式来加, 但对代码侵入性有点高,而且需要对jpa 和 mybatic 进行分别组装sql ;故,最后采用自己写代码封装实现切库的方式来完成, 具体方法依赖:Spring中的AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。
具体实现切库步骤:
1.在platform-common工程中建以下三个类:DataSourceHolder、DynamicDataSource、SwitchDataSource
具体类的实现如下:
package com.star.boss.common.switchdatesource;
/**
* Created by 10000474 on 2018/6/8 0008.
*/
public class DataSourceHolder {
//使用ThreadLocal把数据源与当前线程绑定
private static final ThreadLocal
public static void setDataSource(String dataSourceName) {
dataSources.set(dataSourceName);
}
public static String getDataSource() {
return (String) dataSources.get();
}
public static void clearDataSource() {
dataSources.remove();
}
}
package com.star.boss.common.switchdatesource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* Created by 10000474 on 2018/6/8 0008.
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSource();
}
}
package com.star.boss.common.switchdatesource;
import javax.servlet.*;
import java.io.IOException;
/**
* Created by 10000474 on 2018/6/8 0008.
*/
public class SwitchDataSource implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//此处比较简单,根据自己的业务可扩展;
System.out.println("... start switch datasource ...");
DataSourceHolder.setDataSource("dataSource2"); //这是要切的dataSoure的名称;
System.out.println("... end to switch datasource ...");
System.out.println(DataSourceHolder.getDataSource());
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
2. 在具体项目中的dao配置文件里做以下工作:
先配置两数据源:dataSource1、dataSource2
class="com.alibaba.druid.pool.DruidDataSource"> value="${maxOpenPreparedStatements}"/>
class="com.alibaba.druid.pool.DruidDataSource"> value="${maxOpenPreparedStatements}"/>
并定义动态数据源:dataSource
其它地方配置照旧
3.在具体项目中web.xml 中增加以下配置:
Ok,测试完成;还有一点需要注意的是,一定要在注入bean之前,就要切库,否则一切白费,由于我们项目中前后端分离,又用的注解注入,我开始的时候,想在service层切库,一切貌似正常,实际已经是马后炮了,大家不要犯这样的错误;
另外, 由于一个服务如果要切源,会引起需要初始化多个库的需求,这个需要在flyway中实现,注意一下配置参数又交给zookeep;(请将MamjTest改为有业务意义的名字!)
扩展:
切库的代码,此处因为只是调研版,所以没做优化,真正在项目中,建议用注解的方式来实现,不要手动切,显得比较笨 。
另外,如果分源存数据,会引进事务问题,由于我们项目中,只是查询的时候要切库,存库时已保证了只针对一个库,所以不存在此问题,所以没做研究。