本文共 3509 字,大约阅读时间需要 11 分钟。
MyCat 对自身不支持的 SQL 语句提供一种解决方案——在要执行的 SQL 语句前添加额外的一段由注解。SQL 组织的代码,这样 SQL 就能正确执行,这段代码称之为“注解”。注解的使用相当于对 MyCat 不支持的 SQL 语句做一层透明代理转发,直接交给目标的数据节点进行 SQL 语句执行,其中注解 SQL 用于确定最终执行 SQL 的数据节点。 注解的形式是 :
/*!mycat: sql=注解 Sql 语句*/
/*!mycat: sql=注解 Sql 语句*/真正执行 Sql
使用时将 = 号后的 "注解 Sql 语句" 替换为需要的 SQL 语句即可,后面会提到具体的用法
MyCat 执行 SQL 语句的流程是先进行 SQL 解析处理,解析出分片信息(路由信息)后,然后到该分片对应的物理库上去执行;若传入的 SQL 语句 MyCat 无法解析,则 MyCat 不会去执行;而注解则是告诉 MyCat 按照注解内的 SQL (称之为注解 SQL) 去进行解析处理,解析出分片信息后,将注解后真正要执行的 SQL 语句 (称之为原始 SQL) 发送到该分片对应的物理库上去执行。从原理可以看到,注解只是告诉 MyCat 到何处去执行原始 SQL;因而使用注解前,要清楚的知道该原始 SQL 去哪个分片执行,然后在注解 SQL 中也指向该分片,这样才能使用!例子中的 sharding_id=10010 即是指明分片信息的。若注解 SQL 没有能明确到具体某个分片,譬如例子中的注解 SQL 没有添加 sharding_id=10010 这个条件,则 MyCat 会将原始 SQL 发送到 persons 表所在的所有分片上去执行去,这样造成的后果若是插入语句,则在多个分片上都存在重复记录,同样查询、更新、删除操作也会得到错误的结果
1> MySQL 不支持的语法结构,如 insert …select…
2> 同一个实例内的跨库关联查询,如用户库和平台库内的表关联
1> 注解 SQL 使用 select 语句,不允许使用 delete/update/insert 等语句;虽然 delete/update/insert 等语句也能用在注解中,但这些语句在 SQL 处理中有额外的逻辑判断,从性能考虑,请使用 select 语句
3> 注解 SQL 尽量用最简单的 SQL 语句,如 select id from tab_a where id=’ 10000’
4> 无论是原始 SQL 还是注解 SQL,禁止 DDL 语句
| |
Select | 1> 选择能唯一确定分片的主表,如与用户表关联的时候可以选择用户表 2> 若是业务需要在主表所在的各个分片上都执行可以不加能确定分片的条件 |
Insert | 4> 原始 SQL 中包含的分片字段和注解 SQL 中的分片字段确定的分片务必要一致 5> 对于 insert … select 这种语句,请务必确认插入的记录都在当前查找到的分片上 2> 注解 SQL 包含的分片字段其分片上必须包含这个非分片表 |
Delete | 1> 对于分片表使用要删除记录的表做注解 SQL |
Update | |
Call | 1> 若是要在所有的分片上都执行存储过程,则使用一个在所有分片上都包含的表,不添加任何分片条件调用存储过程 2> 若是单个分片执行,使用能确认到这个分片的表以及分片条件 |
使用注解并不额外增加 MyCat 的执行时间;从解析复杂度以及性能考虑,注解 SQL 应尽量简单。至于一个 SQL 使用注解和不使用注解的性能对比,不存在参考意义,因为前提是 MyCat 不支持的 SQL 才使用注解
新增加 mycat 字符前缀标志 Hintsql : "/** mycat: */"
/*#mycat: db_type=master */ select * from travelrecord; /*!mycat: db_type=slave */ select * from travelrecord; /**mycat: db_type=master */ select * from travelrecord; /*!mycat: sql=select 1 from test */ CREATE PROCEDURE test_proc() BEGIN END ; /*!mycat: sql=select 1 from test */ CREATE TABLE test2(id INT); 注解中语句是节点的表请替换成自己表如 select 1 from 表 ,注解内语句查出来的数据在哪个分片,数据在哪个节点就往哪个节点建
/*!mycat: sql=select 1 from test */ INSERT INTO t_user(id,name) SELECT id,name FROM t_user2; 3> 读写分离 : 配置 MyCat 读写分离后,默认查询都会从读节点获取数据,但是有些场景需要获取实时数据,如果从读节点获取数据可能因延时而无法实现实时,MyCat 支持通过注解 /*balance*/ 来强制从写节点查询数据 :
<1> 事务内的 SQL,默认走写节点,以注解 /*balance*/ 开头,则会根据 schema.xml 的 dataHost 标签属性的 balance="1" 或 "2" 去获取节点
<2> 非事务内的 SQL,开启读写分离默认根据 balance="1" 或 "2" 去获取,以注解 /*balance*/ 开头则会走写节点解决部分已经开启读写分离,但是需要强一致性数据实时获取的场景走写节点
/*balance*/ select a.* from customer a where a.company_id=1; /*!mycat: catlet=demo.catlets.ShareJoin */ select a.*,b.id, b.name as tit from customer a,company b on a.company_id=b.id; /*!mycat: db_type=master */ select * from travelrecord; /*!mycat: db_type=slave */ select * from travelrecord; /*#mycat: db_type=master */ select * from travelrecord; /*#mycat: db_type=slave */ select * from travelrecord; 6> 多租户支持 : 通过注解方式在配置多个 schema 情况下,指定走哪个配置的 schema
web 部分修改 : <1> 在用户登录时,在线程变量(ThreadLocal) 中记录租户的 id
<2> 修改 jdbc 的实现 : 在提交 SQL 时,从 ThreadLocal 中获取租户 id,添加 SQL 注释,把租户的 schema 放到注释中,如 : /*!mycat : schema=test_01 */ sql ;
在 DB 前面建立 proxy 层,代理所有 web 过来的数据库请求。proxy 层是用 mycat 实现的,web 提交的 SQL 过来时在注释中指定 schema,proxy 层根据指定的 schema 转发 SQL 请求
/*!mycat: schema=test_01 */ sql;
转载地址:http://lagab.baihongyu.com/