写点什么

Mycat 多租户方案,kafka 选举原理

作者:MySQL神话
  • 2021 年 11 月 27 日
  • 本文字数:3034 字

    阅读完需:约 10 分钟

return scheme;


}


public static final void remove() {


tenanThreadLocal.remove();


}


}


那控制器层代码的伪代码如下:


public Map findDepts( String tenant, String businessP1 ) {


Map result = new HashMap();


try {


TenantContextHolder.setTenant(tenant);


//调用 service 层代码


} catch(Throw e) {


e.printStackTrace();


result.put("msg", "系统异常");


result.put("code", 1);


} finally {


TenantContextHolder.remove();


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


}


}


如果每个控制器层代码,都需要用上面的模板来做,未免有点。。。所以为了统一处理 Tenant ,目前提供一个给予 Spring AOP 的拦截器。代码如下:


package persistent.prestige.modules.common.tenant;


import org.aopalliance.intercept.MethodInterceptor;


import org.aopalliance.intercept.MethodInvocation;


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 = Fie


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

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享


ldUtils.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 java.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) ReflectHelper


.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();


}


@Override


public Object plugin(Object target) {


// TODO Auto-generated method stub


if (target instanceof StatementHandler) {


return Plugin.wrap(target, this);


} else {


return target;


}


}


@Override


public void setProperties(Properties properties) {


// TODO Auto-generated method stub


}


}


配置如下:


2.2.4 方案优缺点

  • 优点:


对业务代码侵入少,开发人员无需关注数据在哪个逻辑库上,隔离性好。


  • 缺点


如果需要对所有租户的数据进行汇聚的话,需要业务上去实现。


该方案代码:请关注如下代码:

最后

对于很多 Java 工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。


整理的这些资料希望对 Java 开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。


再分享一波我的 Java 面试真题+视频学习详解+技能进阶书籍



本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

用户头像

MySQL神话

关注

还未添加个人签名 2021.11.12 加入

还未添加个人简介

评论

发布
暂无评论
Mycat 多租户方案,kafka选举原理