Donnie

不积跬步无以至千里

springboot+mybatis+macat实现多租户切换访问数据库

多租户实现原理

  1. 使用ThreadLocal记录多租户的数据节点
  2. 通过Mybatis拦截器拦截到要执行的sql
  3. 将当前租户的数据节点封装成mycat注释后的sql

核心源码


    /*
     * 多租户节点持有者
     */
    public class MultiTenantHolder {
    
        //租户节点存储在ThreadLocal
        private static ThreadLocal<String> currentNodeThreadLocal = new ThreadLocal<String>();
    
        public static void setCurrentNode(String currentNode) {
            if (currentNode != null) {
                currentNodeThreadLocal.set(currentNode);
            }
        }
    
    
        public static String getCurrentNode() {
            return currentNodeThreadLocal.get();
        }
    
        /**
         * 清除本地线程变量
         */
        public static void remove() {
            currentNodeThreadLocal.remove();
        }
    }
    


Mybatis拦截器


    @Intercepts(value = {
            @Signature(type = StatementHandler.class,
                    method = "prepare",
                    args = {Connection.class,Integer.class})})
    @Slf4j
    public class MultiTenantInterceptor implements Interceptor {
    
        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);
    
            //拦截要执行的sql
            String sql=(String)metaStatementHandler.getValue("delegate.boundSql.sql");
    
            //获取租户使用节点
            String node = MultiTenantHolder.getCurrentNode();
    
            if(node!=null) {
                sql = preState + node + afterState + sql;
            }
    
            log.info("添加mycat注释的sql =" + sql);
            metaStatementHandler.setValue("delegate.boundSql.sql",sql);
            Object result = invocation.proceed();
    
            MultiTenantHolder.remove();
    
            return result;
        }
    
        @Override
        public Object plugin(Object target) {
    
            return Plugin.wrap(target, this);
        }
    
        @Override
        public void setProperties(Properties properties) {
    
        }
    }

全部源码

https://github.com/donnie0915/MycatDemo

mycat使用

https://www.okhjp.com/post/47

赞赏支持