写点什么

Mycat 多租户方案

  • 2022 年 4 月 16 日
  • 本文字数:2865 字

    阅读完需:约 9 分钟

import org.springframework.beans.factory.annotation.Autowired;


import persistent.prestige.modules.edu.service.UserSchemeService;


public class TenantControlInteceper implements MethodInterceptor {


@Autowired


private UserSchemeService userScemeService;


@Override


public Object invoke(MethodInvocation invocation) throws Throwable {


try {


if("login".equals(invocation.getMethod().getName())) {


return invocation.proceed();


}


System.out.println("控制器层面,,计算 tenant。。。");


Object[] args = invocation.getArguments();


String tenant = "";


if( args != null && args.length > 0) {


tenant = (String)args[0];


}


TenantContextHolder.setTenant(tenant);


return invocation.proceed();


}finally {


TenantContextHolder.remove();


System.out.println("控制器层面,,移除 tenant。。。");


}


}


}


统一处理 Tenant 的设置为移除;此处与代码中的有点差别,是因为,,根据用户登录名获取 tenant 的逻辑放在了上面登录接口中。


只要遵循这样一种编码规范,action 方法的第一个参数的值为 tenant 就好。配置一下拦截器【基于 Spring AOP】


[](()2.2.3、业务承载方法

业务方法无需改变;但是要利用 Mybatis 拦截器改写 SQL。代码和配置如下:


1、工具类


package persistent.prestige.platform.mybatis.Interceptor;


import java.lang.reflect.Field;


import org.apache.commons.lang.reflect.FieldUtils;


public class ReflectHelper {


public static Object getFieldValue(Object obj , String fieldName ){


if(obj == null){


return null ;


}


Field targetField = getTargetField(obj.getClass(), fieldName);


try {


return FieldUtils.readField(targetField, obj, true ) ;


} catch (IllegalAccessException e) {


e.printStackTrace();


}


return null ;


}


public static Field getTargetField(Class<?> targetClass, String fieldName) {


Field field = null;


try {


if (targetClass == null) {


return field;


}


if (Object.class.equals(targetClass)) {


return field;


}


field = FieldUtils.getDeclaredField(targetClass, fieldName, true);


if (field == null) {


field = getTargetField(targetClass.getSuperclass(), fieldName);


}


} catch (Exception e) {


}


return field;


}


public static void setFieldValue(Object obj , String fieldName , Object value ){


if(null == obj){return;}


Field targetField = getTargetField(obj.getClass(), fieldName);


try {


FieldUtils.writeField(targetField, obj, value) ;


} catch (IllegalAccessException e) {


e.printStackTrace();


}


}


}


SQL 拦截类


package persistent.prestige.platform.mybatis.Interceptor;


import java.sql.Connection;


import jav 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》开源 a.util.Properties;


import org.apache.ibatis.executor.statement.RoutingStatementHandler;


import org.apache.ibatis.executor.statement.StatementHandler;


import org.apache.ibatis.mapping.BoundSql;


import org.apache.ibatis.mapping.MappedStatement;


import org.apache.ibatis.plugin.Interceptor;


import org.apache.ibatis.plugin.Intercepts;


import org.apache.ibatis.plugin.Invocation;


import org.apache.ibatis.plugin.Plugin;


import org.apache.ibatis.plugin.Signature;


import org.apache.kahadb.page.Page;


import org.springframework.beans.factory.annotation.Autowired;


import persistent.prestige.modules.common.tenant.TenantContextHolder;


import persistent.prestige.modules.edu.dao.TeacherUserDao;


@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })


public class TenantInterceptor implements Interceptor {


@Override


public Object intercept(Invocation invocation) throws Throwable {


String tenant = TenantContextHolder.getTenant();


if(tenant == null || tenant == "") {


System.out.println("tenant 为空,不需要改写 sql 语句");


return invocation.proceed();


}


if (invocation.getTarget() instanceof RoutingStatementHandler) {


System.out.println("aaaaaaa");


RoutingStatementHandler statementHandler = (RoutingStatementHandler) invocation


.getTarget();


StatementHandler delegate = (StatementHandler) R Java 开源项目【ali1024.coding.net/public/P7/Java/git】 eflectHelper


.getFieldValue(statementHandler, "delegate");


BoundSql boundSql = delegate.getBoundSql();


Object obj = boundSql.getParameterObject();


// 通过反射获取 delegate 父类 BaseStatementHandler 的 mappedStatement 属性


MappedStatement mappedStatement = (MappedStatement) ReflectHelper


.getFieldValue(delegate, "mappedStatement");


// 拦截到的 prepare 方法参数是一个 Connection 对象


Connection connection = (Connection) invocation.getArgs()[0];


// 获取当前要执行的 Sql 语句,也就是我们直接在 Mapper 映射语句中写的 Sql 语句


String sql = boundSql.getSql();


// 给当前的 page 参数对象设置总记录数


System.out.println("处理之前" + sql);


//对 sql 增加 mycat 注解


sql = "/*!mycat:schema=" + tenant + " */" + sql;


System.out.println("加入处理后:" + sql);


ReflectHelper.setFieldValue(boundSql, "sql", sql);


}


return invocation.proceed();


}

最后

ActiveMQ 消息中间件面试专题

  • 什么是 ActiveMQ?

  • ActiveMQ 服务器宕机怎么办?

  • 丢消息怎么办?

  • 持久化消息非常慢怎么办?

  • 消息的不均匀消费怎么办?

  • 死信队列怎么办?

  • ActiveMQ 中的消息重发时间间隔和重发次数吗?


ActiveMQ 消息中间件面试专题解析拓展:




redis 面试专题及答案

  • 支持一致性哈希的客户端有哪些?

  • Redis 与其他 key-value 存储有什么不同?

  • Redis 的内存占用情况怎么样?

  • 都有哪些办法可以降低 Redis 的内存使用情况呢?

  • 查看 Redis 使用情况及状态信息用什么命令?

  • Redis 的内存用完了会发生什么?

  • Redis 是单线程的,如何提高多核 CPU 的利用率?




Spring 面试专题及答案

  • 谈谈你对 Spring 的理解

  • Spring 有哪些优点?

  • Spring 中的设计模式

  • 怎样开启注解装配以及常用注解

  • 简单介绍下 Spring bean 的生命周期


Spring 面试答案解析拓展




高并发多线程面试专题

  • 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?

  • Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。

  • Java 中 wait 和 sleep 方法有什么区别?

  • 如何在 Java 中实现一个阻塞队列?

  • 如何在 Java 中编写代码解决生产者消费者问题?

  • 写一段死锁代码。你在 Java 中如何解决死锁?


高并发多线程面试解析与拓展




jvm 面试专题与解析

  • JVM 由哪些部分组成?

  • JVM 内存划分?

  • Java 的内存模型?

  • 引用的分类?

  • GC 什么时候开始?


JVM 面试专题解析与拓展!



用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
Mycat 多租户方案_Java_爱好编程进阶_InfoQ写作平台