MyCat对自身不支持的Sql语句提供了一种解决方案——在要执行的SQL语句前添加额外的一段由注解SQL组织的代码,这样Sql就能正确执行,这段代码称之为“注解”。注解的使用相当于对mycat不支持的sql语句做了一层透明代理转发,直接交给目标的数据节点进行sql语句执行,其中注解SQL用于确定最终执行SQL的数据节点。注解的形式是:
/*!mycat: sql=注解Sql语句*/
注解的使用方式是:
/*!mycat: 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表所在的所有分片上去执行去,这样造成的后果若是插入语句,则在多个分片上都存在重复记录,同样查询、更新、删除操作也会得到错误的结果!
二、继承关系
HintHandler 有五个子类,HintCatletHandler、HintDataNodeHandler、HintMasterDBHandler、HintSchemaHandler、HintSQLHandler
/**
* 按照注释中包含指定类型的内容做路由解析
*
*/
public interface HintHandler {
public RouteResultset route(SystemConfig sysConfig, SchemaConfig schema,
int sqlType, String realSQL, String charset,
ServerConnection sc,LayerCachePool cachePool,
String hintSQLValue, int hintSqlType, Map hintMap)throws SQLNonTransientException;
--这个方法参数有点多,不够友好
}
/**
* 处理注释中 类型为sql的情况 (按照 注释中的sql做路由解析,而不是实际的sql)
*/
public class HintSQLHandler implements HintHandler {}
/**
* 处理注释中类型为schema 的情况(按照指定schema做路由解析)
*/
public class HintSchemaHandler implements HintHandler{}
/**
* 处理情况 sql hint: mycat:db_type=master/slave<br/>
* 后期可能会考虑增加 mycat:db_type=slave_newest,实现走延迟最小的slave
* @author [email protected]
*/
// /*#mycat:db_type=master*/
// /*#mycat:db_type=slave*/
// /*#mycat:db_type=slave_newest*/
// 强制走 master 和 强制走 slave
public class HintMasterDBHandler implements HintHandler {}
/**
* 处理注释中类型为datanode 的情况
*
* @author zhuam
*/
public class HintDataNodeHandler implements HintHandler{}
/**
* 处理注释中类型为catlet 的情况,每个catlet为一个用户自定义Java代码类,用于进行复杂查询SQL(只能是查询SQL)的自定义执行过程,
* 目前主要用于跨分片Join的人工智能编码
*/
public class HintCatletHandler implements HintHandler {}
三、应用示例
/*#mycat:db_type=master*/ select * from travelrecord
/*!mycat: sql=select 1 from test */create table test2(id int);
如select 1 from 表,注解内语句查出来的数据在哪个分片,数据在那个节点往哪个节点建.
配置了Mycat读写分离后,默认查询都会从读节点获取数据,但是有些场景需要获取实时数据,如果从读节点获取数据可能因延时而无法实现实时,Mycat支持通过注解/balance/来强制从写节点查询数据:
a. 事务内的SQL,默认走写节点,以注解/*balance*/开头,则会根据schema.xml的dataHost标签属性的balance=“1”或“2”去获取节点
b. 非事务内的SQL,开启读写分离默认根据balance=“1”或“2”去获取,以注解/*balance*/开头则会走写节点解决部分已经开启读写分离,但是需要强一致性数据实时获取的场景走写节点
/*balance*/ select a.* from customer a where a.company_id=1;
多租户支持
通过注解方式在配置多个schema情况下,指定走哪个配置的schema。
web部分修改: a.在用户登录时,在线程变量(ThreadLocal)中记录租户的id b.修改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 ;
多表
ShareJoin /*!mycat:catlet=demo.catlets.ShareJoin */ select a.*,b.id, b.name as tit from customer a,company b on a.company_id=b.id;