一、Mycat和Sharding-jdbc的區(qū)別
1)mycat是一個(gè)中間件的第三方應(yīng)用,sharding-jdbc是一個(gè)jar包
2)使用mycat時(shí)不需要改代碼,而使用sharding-jdbc時(shí)需要修改代碼
Mycat(proxy中間件層):

Sharding-jdbc(TDDL為代表的應(yīng)用層):

二、Mycat分片join
在前面的文章Mysql系列四:數(shù)據(jù)庫(kù)分庫(kù)分表基礎(chǔ)理論中,已經(jīng)說(shuō)過(guò)分庫(kù)分表需要應(yīng)對(duì)的技術(shù)難題有如下幾個(gè):
1.)分布式全局唯一id
2.)分片規(guī)則和策略
3.)跨分片技術(shù)問(wèn)題
4.)跨分片事物問(wèn)題
下面我們來(lái)看一下Mycat是如何解決跨分片技術(shù)問(wèn)題——分片join的
1. 使用全局表方式解決跨分片join問(wèn)題
1.1 先在server.xml里面全局表一致性檢測(cè)
<property name="useGlobleTableCheck">1</property><!-- 1為開(kāi)啟全局表一致性檢測(cè)、0為關(guān)閉 -->
1.2 在schema.xml里面配置全局表
<table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3"/>
全局表說(shuō)明:
1)全局表的插入、更新操作會(huì)實(shí)時(shí)在所有節(jié)點(diǎn)上執(zhí)行,保持各個(gè)分片數(shù)據(jù)的一致性
2)全局表的查詢(xún)操作只從一個(gè)節(jié)點(diǎn)上獲取
3)全局表可以跟任何一個(gè)表進(jìn)行join操作
2. 使用Share Join方式解決跨分片join問(wèn)題
Share Join是一個(gè)簡(jiǎn)單的跨分片join,基于HBT(Human Brain Tech)的方式實(shí)現(xiàn)。
原理:解析SQL語(yǔ)句,拆分成單表的SQL語(yǔ)句執(zhí)行,然后把各個(gè)節(jié)點(diǎn)的數(shù)據(jù)匯集。
示例:
/*!mycat:catlet=io.mycat.catlets.ShareJoin*/select*fromemployee a, employee_detail bwherea.id=b.id;
說(shuō)明:目前只支持兩張分片表的Join,如果要支持多張表需要自己改造程序代碼或者改造Mycat的源代碼
對(duì)應(yīng)Mycat源碼:
io.mycat.catlets.ShareJoin
io.mycat.catlets.Catlet
public class ShareJoin implements Catlet
3. 使用ER Join方式解決跨分片join問(wèn)題
ER表也叫父子表,子表存儲(chǔ)在哪個(gè)分片上依賴(lài)于父表的存儲(chǔ)位置,并且和父表存儲(chǔ)同一個(gè)分片上,即子表的記錄與所關(guān)聯(lián)的父表記錄存放在同一個(gè)數(shù)據(jù)分片上,從而解決跨庫(kù)join的問(wèn)題
在schema.xml里面的配置
<table name="customer" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-intfile"><childTable name="orders" primaryKey="ID" joinKey="customer_id" parentKey="id"><childTable name="order_items" joinKey="order_id" parentKey="id"/></childTable><childTable name="customer_addr" primaryKey="ID" joinKey="customer_id" parentKey="id"/></table>
說(shuō)明:
childTable:標(biāo)簽用來(lái)聲明子表:
joinKey:聲明子表的那個(gè)字段和父表關(guān)聯(lián)
parentKey:聲明父表的關(guān)聯(lián)主鍵
primaryKey:父表自身的主鍵
三、Mycat分頁(yè)中的坑
Mycat分頁(yè)的大坑一定要注意:
在對(duì)應(yīng)的分片上去查詢(xún)分頁(yè)數(shù)據(jù)的時(shí)候是從第一條記錄開(kāi)始掃描,然后再取出對(duì)應(yīng)的分頁(yè)數(shù)據(jù),如
SELECT*FROMcustomerORDERBYid LIMIT1000100,100;
這個(gè)sql語(yǔ)句被Mycat轉(zhuǎn)化后
1->dn1{SELECT*FROMcustomerORDERBYid LIMIT0,1000100}2->dn2{SELECT*FROMcustomerORDERBYid LIMIT0,1000100}
所以要在Mycat的server.xm里面開(kāi)啟使用非堆內(nèi)存。否則內(nèi)存會(huì)爆掉
<property name="useOffHeapForMerge">1</property>
優(yōu)化:
1)先查出id
SELECTidFROMcustomerORDERBYid LIMIT1000100,100;
這個(gè)sql語(yǔ)句被mycat轉(zhuǎn)化后
1->dn1{SELECTidFROMcustomerORDERBYid LIMIT0,1000100}2->dn2{SELECTidFROMcustomerORDERBYid LIMIT0,1000100}
2) 拿到所有的id以后再取獲取需要的數(shù)據(jù)
SELECT*FROMcustomerwhereidin(1,2,3....);
這個(gè)sql語(yǔ)句被mycat轉(zhuǎn)化后
1->dn1{SELECT*FROMcustomerwhereidin(1,2,3....);}2->dn2{SELECT*FROMcustomerwhereidin(1,2,3....);}
四、Mycat注解
1. Mycat不支持的SQL語(yǔ)句:
1)? 某些SQL語(yǔ)法,如insert into......select.....
2)? 跨庫(kù)關(guān)聯(lián)查詢(xún)
3)存儲(chǔ)過(guò)程創(chuàng)建
4)存儲(chǔ)過(guò)程調(diào)用
所以Mycat提供Mycat注解來(lái)解決上面這些不支持的SQL語(yǔ)句
Mycat的解決辦法:Mycat注解
語(yǔ)法:
/*!mycat:sql=Mycat注解SQL語(yǔ)句*/真正執(zhí)行的SQL!號(hào)方式
/*#mycat:sql=Mycat注解SQL語(yǔ)句*/真正執(zhí)行的SQL?#號(hào)方式
/**mycat:sql=Mycat注解SQL語(yǔ)句*/真正執(zhí)行的SQL*號(hào)方式
原理:
使用mycat不支持的SQL替換mycat支持的SQL,運(yùn)行Mycat不支持的SQL

Mycat注解規(guī)范:
1) 注解SQL使用select語(yǔ)句,不允許使用delete/update/insert等語(yǔ)句;雖然delete/update/insert等語(yǔ)句也能用在注解中,但這些語(yǔ)句在Sql處理中有額外的邏輯判斷,從性能考慮,請(qǐng)使用select語(yǔ)句。
2) 注解SQL禁用表關(guān)聯(lián)語(yǔ)句。
3) 注解SQL盡量用最簡(jiǎn)單的SQL語(yǔ)句,如select id from tab_a where id=’10000’(如果必要,最好能在注解中指定分片)
4) 無(wú)論是原始SQL 還是注解SQL,禁止DDL語(yǔ)句
5) 能不用注解的盡量不用
2. Mycat注解解決不支持insert into......select.....
/*!mycat:sql=select 1*/insertintotravelrecord(id,user_id,traveldate,fee,days)select3,'Tom','20180826',100,8;
3. Mycat注解創(chuàng)建表
/*!mycat:sql=select 1 from test */createtabletest2(idint);
4. Mycat注解創(chuàng)建存儲(chǔ)過(guò)程
/*!mycat:sql=select 1 from test */createprocedure'test_proc()'beginend;
5. Mycat注解調(diào)用存儲(chǔ)過(guò)程
/*!mycat:sql=select * from user where id=1 */call test_proc();
6. Mycat注解讀寫(xiě)分離數(shù)據(jù)源選擇
/*!mycat:db_type=master */select*from travelrecord;(強(qiáng)制走主庫(kù))/*!mycat:db_type=slave */select*fromtravelrecord;(強(qiáng)制走從庫(kù))
五、Catlet使用
通過(guò)Catlet支持跨分片復(fù)雜SQL實(shí)現(xiàn)以及存儲(chǔ)過(guò)程支持等等
使用方式:通過(guò)mycat注解方式來(lái)執(zhí)行
1. 跨分片聯(lián)合查詢(xún)注解支持
/*!mycat:catlet=io.mycat.catlets.ShareJoin */selecto.id,u.*fromordero,useruwhereo.user_id=u.id;
2. 批量插入與ID自增長(zhǎng)結(jié)合的支持
/*!mycat:catlet=io.mycat.route.sequence.BatchInsertSequence */insertintouser(name)values('Tom'),('Cat'),('Alan');
sharhing-jdbc的用法請(qǐng)參考下面的博客:
https://blog.csdn.net/forezp/article/details/94174114