第一种:

  优点:支持进一步分片

  缺点:schema配置繁琐

注解式  /*!mycat:schema=[schemaName] */   注意:这在navicat 里面是会报错的,请用命令行登陆mycat 来测试

mysql> explain /*!mycat:schema=USER1 */ select * from order;

可以在每个sql语句前面添加此注解,Mybatis 可以重写 MappedStatement  的 getBoundSql 来添加。

不管使用什么方式,感觉这都很搓。还要手动在Mycat schema.xml 中添加很冗长的 配置。

<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="USER1" checkSQLschema="false" sqlMaxLimit="10000">
    .....
  </schema> <schema name="USER2" checkSQLschema="false" sqlMaxLimit="10000">
  ......  
  </schema>
以下省略无数个 schema

第二种:使用枚举分片实现多租户

  优点:schema.xml 配置相对简洁

  缺点:不可进一步分片

explain /*!mycat:schema=[schema] */ /*!mycat:dataNode=dn1 */ select * from order;

创建分片枚举规则文件.

cat sharding-by-enum.txt
= = =

修改rule.xml的 function

    <function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">sharding-by-enum.txt</property>
<property name="type">0</property>
<!-- <property name="mapFile">partition-hash-int.txt</property> -->
</function>

测试枚举分片命中率,这就可以使用枚举分片,达到多租户效果

枚举分片,解决查询分片命中问题
mysql> explain select * from order a left join detail b on a.id = b.orderId where a.sharding_id = 0;
+-----------+----------------------------------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+----------------------------------------------------------------------------------------------------------------------+
| dn1 | select * from order a left join detail b on a.id = b.orderId where a.sharding_id = 0 |
+-----------+----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
两个表,都有枚举分片字段
mysql> explain select * from order a left detail b on a.id = b.orderId where a.sharding_id and b.sharding_id = 0;
+-----------+----------------------------------------------------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------+
| dn1 | select * from order a left detail b on a.id = b.orderId where a.sharding_id and b.sharding_id = 0 |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec) mysql> 没有命中条件,造成全盘扫描 mysql> explain select * from order a left join detail b on a.id = b.orderId;
+-----------+----------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+----------------------------------------------------------------------------------------------+
| dn1 | select * from rder a left join detail b on a.id = b.orderId |
| dn2 | select * from rder a left join detail b on a.id = b.orderId |
| dn3 | select * from rder a left join detail b on a.id = b.orderId |
+-----------+----------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec) UPDATE Database changed
mysql> explain update detail set itemNum='' where id = 8079
-> ;
+-----------+--------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+--------------------------------------------------------------+
| dn1 | update detail set itemNum='' where id = 8079 |
| dn2 | update detail set itemNum='' where id = 8079 |
| dn3 | update detail set itemNum='' where id = 8079 |
+-----------+--------------------------------------------------------------+
3 rows in set (0.02 sec) 分片字段不能被更新
mysql> explain update detail set itemNum='',shardingId=0 where id = 8079;
ERROR 1064 (HY000): Sharding column can't be updated DETAIL->SHARDINGID 加上分片字段 mysql> explain update order set itemNum='100' where id = 8079 and shardingId = 0;
+-----------+---------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+---------------------------------------------------------------------------------+
| dn1 | update order set itemNum='100' where id = 8079 and shardingId = 0 |
+-----------+---------------------------------------------------------------------------------+
1 row in set (0.00 sec) 删除,同样全盘扫描
mysql> explain delete detail where id = 8079;
+-----------+--------------------------------------------+
| DATA_NODE | SQL |
+-----------+--------------------------------------------+
| dn1 | delete detail where id = 8079 |
| dn2 | delete detail where id = 8079 |
| dn3 | delete detail where id = 8079 |
+-----------+--------------------------------------------+
3 rows in set (0.00 sec) 强制命中条件
mysql> explain delete detail where id = 8079 and shardingId = 0;
+-----------+---------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+---------------------------------------------------------------+
| dn1 | delete detail where id = 8079 and shardingId = 0 |
+-----------+---------------------------------------------------------------+
1 row in set (0.00 sec) 全局表与分配表 inner join 以及 left jion right jion 都可以命中枚举
mysql> explain select * from user a inner join order b where a.id=b.userId and b.shardingId = 0;
+-----------+----------------------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+----------------------------------------------------------------------------------------------------------+
| dn1 | select * from user a inner join order b where a.id=b.userId and b.shardingId = 0|
+-----------+----------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec) mysql> explain select * from user a right join order b on a.id = b.userId where b.shardingId = 0;
+-----------+------------------------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+------------------------------------------------------------------------------------------------------------+
| dn1 |select * from user a right join order b on a.id = b.userId where b.shardingId = 0|
+-----------+------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

无论是用哪一种方式,而枚举方式的schema还简单一点

只需要添加dataNode,即可,没有第一种的方式那么膨胀XML

    <dataNode name="dn1" dataHost="localhost1" database="db1" />

关于这个分片标识可以记录再session里面(配合redis session ,不再考虑session 导致的内存溢出问题,万一溢出,那非常值得开心,用户量已经那么高了)

/**
* Created by laizhenwei
*/
@Component("sessionAttributes")
@Scope(scopeName = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionAttributes implements Serializable { private static final long serialVersionUID = -8521804511291179982L; //用户分片标识
private Integer shardId; /**
* 获取当前用户的分片标识
*/
public Integer getCurrentShardId() {
Optional<Integer> shardIdOptional = Optional.ofNullable(shardId);
return shardIdOptional.orElseThrow(() -> new RuntimeException("无法获取当分片标识!"));
}

以上方式不支持多线程.请不要让 SessionAttributes  离开Controller 作用域.如果整个程序都不涉及多线程,那么随意在那一层注入

支持多线程方式,借助 InheritableThreadLocal然后写一个过滤器

/**
* Created by laizhenwei
*/
public class ShardContextFilter implements Filter { @Autowired
private SessionAttributes sessionAttributes; @Override
public void destroy() {
// Do nothing
} @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ContextHolder.create(createContext());
chain.doFilter(request, response);
} @Override
public void init(FilterConfig config) throws ServletException {
// Do nothing
} private Context createContext() {
//....
return context;
} }

当然可以使用注解来过滤需要分片命中的请求的规则

@WebFilter(filterName="contextFilter",urlPatterns = {"/addOrder/*","/whatever/*"})

我喜欢在Security需要验证的资源添加到过滤器链,这样我不需要考虑资源规则问题

 http.addFilterAfter(contextFilter(), FilterSecurityInterceptor.class);

最后总结一下:

如果单个用户的数据还需要进一步分片,那么只能使用schema的注解拦截实现,

如果单个用户数据,不需要再进一步分片,那么使用枚举分片会简单一些

但是,无论使用哪种方式,都难免需要人工处理schema.xml,除非开始就预建了很多schema或者dataNode,否则再添加的时候,mycat不能像nginx一样reload配置文件,必须停机重启读取配置文件

mongodb也有类似的多租户分片规则[tag]分片,但是这样无法处理分片数据不均衡,所以还是不建议使用tag分片.

定制业务适合的片键,让mongodb自动分片,能很大程度减少维护成本.

两种实现方式mycat多租户,枚举分片,注解拦截的更多相关文章

  1. Web APi之认证(Authentication)两种实现方式【二】(十三)

    前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底 ...

  2. Android中BroadcastReceiver的两种注册方式(静态和动态)详解

    今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式. BroadcastReceiver也就是"广播接收者"的意思,顾名思义,它就是用来 ...

  3. Android中Fragment与Activity之间的交互(两种实现方式)

    (未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...

  4. JavaScript 函数的两种声明方式

    1.函数声明的方式 JavaScript声明函数有两种选择:函数声明法,表达式定义法. 函数声明法 function sum (num1 ,num2){ return num1+num2 } 表达式定 ...

  5. Redis两种持久化方式(RDB&AOF)

    爬虫和转载请注明原文地址;博客园蜗牛:http://www.cnblogs.com/tdws/p/5754706.html Redis所需内存 超过可用内存怎么办 Redis修改数据多线程并发—Red ...

  6. struts2+spring的两种整合方式

    也许有些人会因为学习了struts1,会以为struts2.struts1与spring的整合也是一样的,其实这两者相差甚远.下面就来讲解一下struts2与spring的整合两种方案.(部分转载,里 ...

  7. easyui datagride 两种查询方式

    easyui datagride 两种查询方式function doReseach() { //$('#tt').datagrid('load', { // FixedCompany: $('.c_s ...

  8. 【Visual Lisp】两种出错处理方式

    两种出错处理方式:一种是对出错函数进行重定义,一种是对错误进行捕捉处理. ;;============================================================= ...

  9. 两种include方式及filter中的dispatcher解析

    两种include方式 我自己写了一个original.jsp,另外有一个includedPage.jsp,我想在original.jsp中把includedPage.jsp引进来有两种方式: 1.& ...

随机推荐

  1. linkin大话面向对象--接口

    接口(interface)的概念,掌握接口很重要,以后所有的编程都要面向接口编程.其实接口的内涵就7个字:规范和实现分离. 抽象类是从多个类中抽象出来的模板,若要将这种抽象进行得更彻底,就得用到一种特 ...

  2. NW.js 简介与使用

    简介 (1)以网络最流行的技术编写原生应用程序的新方法 (2)基于HTML5, CSS3, JS and WebGL而编写 (3)完全支持nodejs所有api及第三方模块 (4)可以使用DOM直接调 ...

  3. mavean的依赖传递和排除依赖

    三个mavean项目 A  .B. C 如果B依赖A(A先执行clean package命令) 那么B得pom.xml文件里面就写 <dependency> <groupId> ...

  4. mysql pdo数据库连接

    MYSQL $conn = @mysql_connect('localhost','root','root');//括号的里的分别代表主机.用户名.密码 mysql_select_db('test', ...

  5. [DeeplearningAI笔记]Batch NormalizationBN算法Batch归一化_02_3.4-3.7

    Batch Normalization Batch归一化 觉得有用的话,欢迎一起讨论相互学习~Follow Me 3.4正则化网络的激活函数 Batch归一化会使你的参数搜索问题变得很容易,使神经网络 ...

  6. Django中模板的用法简介

    1. 模板系统的介绍 Django作为一个Web框架,其模板所需的HTML输出静态部分以及动态内容插入 模板由HTML代码和逻辑控制代码构成 Django框架的模板语言的语法格式: {{var_nam ...

  7. bzoj 3864: Hero meet devil [dp套dp]

    3864: Hero meet devil 题意: 给你一个只由AGCT组成的字符串S (|S| ≤ 15),对于每个0 ≤ .. ≤ |S|,问 有多少个只由AGCT组成的长度为m(1 ≤ m ≤ ...

  8. BZOJ 4514: [Sdoi2016]数字配对 [费用流 数论]

    4514: [Sdoi2016]数字配对 题意: 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数 ...

  9. Vue打包后出现一些map文件

    Vue打包后出现一些map文件的解决办法: 问题: 可能很多人在做vue项目打包,打包之后js中,会自动生成一些map文件,那我们怎么把它去掉不要呢? 1,运行  cnpm run build  开始 ...

  10. 关于node的基础理论,书上看来的

    最近看了一本书,说了一些Node.js的东西,现在来记录一下,让自己记得更牢靠一点. 在书上,是这样介绍的:Node.js模型是源于Ruby的Event Machine 和 Python的Twiste ...