SpringBoot Mybatis Mycat 多租户数据库实现

SpringBoot Mybatis Mycat 多租户数据库实现_第1张图片

0x01: Mycat

下载
wget http://dl.mycat.io/1.6.7.3/20190927161129/Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz
配置

server.xml,Mycat服务器配置,默认端口8066




    
        0
        0
        2
        0
        1
        1m
        1k
        0
        384m
        true
    

    
    
        
        root
        
        mycat_test
    


schema.xml,Mycat和Mysql节点映射配置




    
    
        
        
    
    
    
    

    
    
        select user()
        
        
        
    

0x02:Spring Boot

数据源配置
#mycat连接信息
spring.datasource.url=jdbc:mysql://localhost:8066/mycat_test?serverTimezone=GMT
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

#mybatis拦截器配置
mybatis.config-location=classpath:mybatis.xml
Mybatis

mybatis.xml插件配置





    
        
        
    

    
        
    

        
    
        
        
    


拦截器
//拦截StatementHandler的prepare方法
@Intercepts(value = {
        @Signature(type = StatementHandler.class,
                method = "prepare",
                args = {Connection.class,Integer.class})})
public class MyInterceptor implements Interceptor {
    // 修改sql,添加前后缀
    private static final String preState="/*!mycat:datanode=";
    private static final String afterState="*/";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler=(StatementHandler)invocation.getTarget();
        MetaObject metaStatementHandler=SystemMetaObject.forObject(statementHandler);
        Object object=null;
        //分离代理对象链
        while(metaStatementHandler.hasGetter("h")){
            object=metaStatementHandler.getValue("h");
            metaStatementHandler=SystemMetaObject.forObject(object);
        }

        //获取sql
        String sql=(String)metaStatementHandler.getValue("delegate.boundSql.sql");

        //根据会话上下文,获取节点标识
        String node=(String) SessionUtil.getSession().getAttribute("appId");
        if(node!=null) {
            //重写sql,适配mycat
            sql = preState + node + afterState + sql;
        }

        System.out.println("sql is "+sql);
        metaStatementHandler.setValue("delegate.boundSql.sql",sql);
        Object result = invocation.proceed();
        System.out.println("Invocation.proceed()");
        return result;
    }

    // 返回当前拦截的对象(StatementHandler)的动态代理
    // 当拦截对象的方法被执行时, 动态代理中执行拦截器intercept方法.
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        String prop1 = properties.getProperty("prop1");
        String prop2 = properties.getProperty("prop2");
        System.out.println(prop1 + "------" + prop2);
    }
}
总结

以上为关键实现,主要过程如下:

  • 搭建 Mycat 服务,设置提供的数据库信息

  • 配置Mycat动态映射的两个节点,Mycat根据sql语句中的/*!mycat:datanode=dn1*/进行动态切换数据源后执行sql

  • 配置 SpringBoot 的 Mycat 数据源连接

  • 配置 Mybatis 的拦截器插件

  • 配置 Mybatis 拦截器实现,根据上下文节点,改写 sql

注意

  • 生产可采用Mycat集群,集群用ZK管理,以动态实例化数据源

喜欢,在看

你可能感兴趣的:(数据库,mybatis,mysql,jdbc,mycat)