Mybatis插件动态数据库链接

Mybatis插件动态数据库链接

场景:
springboot+mybatis-plus+mysql+clickhouse
同时整合了mysql和clickhouse 并且clickhouse设置了集群
要求对clickhouse数据库链接做负载均衡
算法采用当前线程Id的hash算法

解决方案:

  1. 自定义 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<CkTableColumnEntity> columns);

  void insert(@Param("tableName") String tableName, @Param("columnDataList") List<List<Object>> columnDataList,@Param("columns") List<CkTableColumnEntity> columns);
}

4.sql的xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.renren.modules.ck.dao.CkMybatisDao">
  <select id="createCkTable">

    create table clickhouse.${table.tableName}(
    <foreach collection="columns" item="column" separator=",">
      ${column.columnName} ${column.dataType}
    </foreach>
    )
    Engine = ReplacingMergeTree primary key ${table.pkColumn}
    order by
    ${table.pkColumn}
  </select>

  <select id="insert">
    insert into clickhouse.${tableName}
    <foreach collection="columns" item="column" separator="," open="(" close=")">
      ${column.columnName}
    </foreach>
    values
    <foreach collection="columnDataList" item="columnData" separator="," >
        <foreach collection="columnData" item="value" separator="," open="(" close=")">
          ${value}
        </foreach>
    </foreach>
  </select>
</mapper>

所有准备工作完成 直接在Service中注入CkMybatisDao 就可操作clickhouse了 并且 其他Dao依然是操作mysql

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值