实现读写分离的两种方法
1、第一种方式是我们最常用的方式,就是定义2个数据库连接,一个是MasterDataSource,另一个是SlaveDataSource。更新数据时我们读取MasterDataSource,查询数据时我们读取SlaveDataSource。
2、第二种方式动态数据源切换,就是在程序运行时,把数据源动态织入到程序中,从而选择读取主库还是从库。主要使用的技术是:Annotation(spring 注解),spring AOP(面向切面) ,反射。
我采用的方式为第二种,废话不多说上代码吧。
一、DataSourceHandler(数据源的Handler类)
/**
* 数据源的Handler类
*/
public class DataSourceHandler {
// 数据源名称线程池
public static final ThreadLocal<String> holder = new ThreadLocal<String>();
/**
* 在项目启动的时候将配置的读、写数据源加到holder中
*/
public static void putDataSource(String datasource) {
System.err.println("putDataSource:....."+datasource);
holder.set(datasource);
}
/**
* 从holer中获取数据源字符串
*/
public static String getDataSource() {
return holder.get();
}
}
二、ChooseDataSource(获取数据源,用于动态切换数据源)
public class ChooseDataSource extends AbstractRoutingDataSource {
public static Map<String, List<String>> METHOD_TYPE_MAP = new HashMap<String, List<String>>();
protected Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 实现父类中的抽象方法,获取数据源名称
* @return
*/
protected Object determineCurrentLookupKey() {
logger.info("determineCurrentLookupKey:....."+DataSourceHandler.getDataSource());
return DataSourceHandler.getDataSource();
}
// 设置方法名前缀对应的数据源
public void setMethodType(Map<String, String> map) {
for (String key : map.keySet()) {
List<String> v = new ArrayList<String>();
String[] types = map.get(key).split(",");
for (String type : types) {
if (StringUtils.isNotBlank(type)) {
v.add(type);
}
}
METHOD_TYPE_MAP.put(key, v);
}
}
}
三、DataSourceAspect( 切换数据源(不同方法调用不同数据源))
/**
* 切换数据源(不同方法调用不同数据源)
*/
@Aspect
@Component
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class DataSourceAspect {
protected Logger logger = LoggerFactory.getLogger(this.getClass());
@Pointcut("execution(* com.ssm.dao.DAO.*(..))")
public void aspect() {
}
/**
* 配置前置通知,使用在方法aspect()上注册的切入点
*/
@Before("aspect()")
public void before(JoinPoint point) {
String className = point.getTarget().getClass().getName();
String method = point.getSignature().getName();
logger.info("切入具体位置:"+className + "." + method + "(" + StringUtils.join(point.getArgs(), ",") + ")");
logger.info("切入类名称:"+className);
logger.info("切入类方法名称:"+method);
logger.info("方法参数:"+StringUtils.join(point.getArgs(), ","));
try {
for (String key : ChooseDataSource.METHOD_TYPE_MAP.keySet()) {
for (String type : ChooseDataSource.METHOD_TYPE_MAP.get(key)) {
if (method.startsWith(type)) {
DataSourceHandler.put