【Mycat1.6之HintSQLHandler源码阅读】

 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;

猜你喜欢

转载自gaojingsong.iteye.com/blog/2376227