场景:
springboot+mybatis-plus+mysql+clickhouse
同时整合了mysql和clickhouse 并且clickhouse设置了集群
要求对clickhouse数据库链接做负载均衡
算法采用当前线程Id的hash算法
解决方案:
- 自定义 mybatis Interceptor 拦截Executor
package io.renren.modules.ck.config;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.baomidou.mybatisplus.core.executor.MybatisSimpleExecutor;
import io.renren.common.utils.CkMybatisUtil;
import io.renren.modules.ck.dao.CkMybatisDao;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.Transaction;
import java.lang.reflect.Field;
import java.util.Properties;
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class CkDataSourceInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
if (args[0] instanceof MappedStatement) {
MappedStatement ms = (MappedStatement) args[0];
String id = ms.getId();
if (id.contains(CkMybatisDao.class.getName())) {
Object target = invocation.getTarget();
MybatisSimpleExecutor executor=(MybatisSimpleExecutor) target;
Transaction transaction = executor.getTransaction();
DruidPooledConnection connection = CkMybatisUtil.getDataSource().getConnection();
Class extends Transaction> transactionClass = transaction.getClass();
Field connectionField = transactionClass.getDeclaredField("connection");
connectionField.setAccessible(true);
connectionField.set(transaction,connection);
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
2.注册CkDataSourceInterceptor
package io.renren.modules.ck.config;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
@org.springframework.context.annotation.Configuration
public class MybatisInterceptorConfig {
//将插件加入到mybatis插件拦截链中
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> {
//插件拦截链采用了责任链模式,执行顺序和加入连接链的顺序有关
CkDataSourceInterceptor interceptor = new CkDataSourceInterceptor();
configuration.addInterceptor(interceptor);
};
}
}
3.CkMybatisUtil 获取数据源方法 在这里可以写负载均衡算法处理数据源
package io.renren.common.utils;
import com.alibaba.druid.pool.DruidDataSource;
public class CkMybatisUtil {
public static DruidDataSource getDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl("jdbc:clickhouse://localhost:8123/clickhouse");
druidDataSource.setUsername("default");
druidDataSource.setDriverClassName("ru.yandex.clickhouse.ClickHouseDriver");
return druidDataSource;
}
}
4.clickhouse mapper映射的Dao接口
package io.renren.modules.ck.dao;
import io.renren.modules.ck.entity.CkTableColumnEntity;
import io.renren.modules.ck.entity.CkTableInfoEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface CkMybatisDao {
void createCkTable(@Param("table") CkTableInfoEntity table, @Param("columns") List columns);
void insert(@Param("tableName") String tableName, @Param("columnDataList") List> columnDataList,@Param("columns") List columns);
}
4.sql的xml文件
所有准备工作完成 直接在Service中注入CkMybatisDao 就可操作clickhouse了 并且 其他Dao依然是操作mysql



