第一种:

  优点:支持进一步分片

  缺点: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. Linux指令--cd,pwd

    本文参照博客做了修改和总结,感谢作者的分享.http://www.cnblogs.com/peida/archive/2012/10/24/2736501.html cd 命令可以说是Linux中最基 ...

  2. lambda高级进阶--表达式参数

    1,现在我们封装一个方法,来提供一个比较器,显然比较器是拥有两个参数的--用来比较的两个值. public class Linkin { public static String[] sort(Str ...

  3. Tomcat 的设计模式分析

    最近在研究tomcat,手上有一份尚硅谷的tomcat设计模式的资料,翻开看了看个人觉得写得还是很好的.设计模式一般都是在有一定的代理积累之后才能用到的相关的这种解决方案.常用的一共有23种设计模式, ...

  4. Spring 4.x (二)

    1 静态代理 PersonDAO.java package com.xuweiwei.staticproxy; public interface PersonDAO { public void sav ...

  5. Hibernate (四)

    1 懒加载 (感觉用处不是很大) 需要的时候加载,不需要的时候就不加载. 1.1 环境的搭建 hibernate.cfg.xml <?xml version='1.0' encoding='ut ...

  6. oracle pl/sql中的循环及if语句

    for循环 /* for循环打印1到10 */ set serveroutput on; declare begin .. loop dbms_output.put_line(i); end loop ...

  7. Ajax异步信息抓取方式

    淘女郎模特信息抓取教程 源码地址: cnsimo/mmtao 网址:https://0x9.me/xrh6z   判断一个页面是不是Ajax加载的方法: 查看网页源代码,查找网页中加载的数据信息,如果 ...

  8. JavaScript函数调用模式

    1.方法调用模式: var myObj = { value : 0; increment:function(inc){ this.value += typeof inc === 'number' ? ...

  9. http目录显示时间与服务器相差8小时

    一直用nginx做http服务,代码里访问过文件地址,并未认真关注过访问http目录下的时间戳.今天浏览文件的时候发现一个问题.web上显示的文件时间戳与服务器时间相比差8个小时.具体表现看下图: w ...

  10. BZOJ 2734: [HNOI2012]集合选数 [DP 状压 转化]

    传送门 题意:对于任意一个正整数 n≤100000,如何求出{1, 2,..., n} 的满足若 x 在该子集中,则 2x 和 3x 不能在该子集中的子集的个数(只需输出对 1,000,000,001 ...