日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql分库分表方案之sharding-jdbc使用(非demo示例)

發(fā)布時(shí)間:2025/3/8 数据库 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql分库分表方案之sharding-jdbc使用(非demo示例) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

選擇開源核心組件的一個(gè)非常重要的考慮通常是社區(qū)活躍性,一旦項(xiàng)目團(tuán)隊(duì)無法進(jìn)行自己后續(xù)維護(hù)和擴(kuò)展的情況下更是如此。

關(guān)于分庫分表和讀寫分離、主從

一般來說,需要分庫分表的系統(tǒng)是流量比較大的,而且比較容易出現(xiàn)峰值的比如說打折/活動(dòng)的時(shí)候;其次,當(dāng)單機(jī)扛不住業(yè)務(wù)流量的時(shí)候,分庫分表一定不是第一選擇,在分庫分表之前,應(yīng)該先保證垂直拆分完成了,子系統(tǒng)內(nèi)都是高內(nèi)聚的,其次基于Master-Slave的讀寫分離或者模糊查詢很多的,可能NoSQL比如elastic就引流去很大一部分了。當(dāng)讀寫分離也做完了,主庫只剩下關(guān)鍵業(yè)務(wù)邏輯之后,流量還是很高,這個(gè)時(shí)候才開始考慮分庫分表。因?yàn)橄鄬?duì)于讀寫分離、垂直拆分,分庫分表對(duì)開發(fā)和運(yùn)維的要求多得多,如果確定業(yè)務(wù)一兩年內(nèi)不會(huì)劇增的,盲目引入只會(huì)導(dǎo)致成本高昂(尤其是各種SQL限制)。

其次,分庫分表會(huì)增加N倍的數(shù)據(jù)庫服務(wù)器,一般來說是4的倍數(shù),如果某個(gè)應(yīng)用說要做分庫分表,又只有兩臺(tái)機(jī)器,那完全就是湊熱鬧。

讀寫分離和分庫分表應(yīng)該來說是前后的兩件事比較合理,不少人將這兩個(gè)事情混到一起去講準(zhǔn)確的說不合理的。分庫分表通常更多的是用于純粹的OLTP的事情,讓系統(tǒng)可以水平擴(kuò)展。而讀寫分離更多的是為了把一部分可以容忍短時(shí)延遲/不保證100%(但應(yīng)該在99%以上)準(zhǔn)確的查詢路由到查詢庫,準(zhǔn)確的說是對(duì)業(yè)務(wù)根據(jù)優(yōu)先級(jí)做個(gè)歸類,這些查詢從資源消耗的角度來說相對(duì)邏輯上的PK查詢要高幾倍到數(shù)百倍,比如說查詢某個(gè)人過去3個(gè)月的交易情況,但他從業(yè)務(wù)角度并不算是DSS概念,比如說查詢已經(jīng)T-N的訂單/針對(duì)這些訂單進(jìn)行導(dǎo)出,并針對(duì)這個(gè)單子可能會(huì)進(jìn)行一些操作,甚至人工修改狀態(tài)。通過把這些功能從核心的訂單/交易/資金OLTP中拆分出去,可以保證核心業(yè)務(wù)系統(tǒng)不會(huì)因?yàn)橐粋€(gè)異常操作比如SQL不合理導(dǎo)致系統(tǒng)出現(xiàn)業(yè)務(wù)負(fù)載增加外的額外抖動(dòng)因素。

從系統(tǒng)設(shè)計(jì)角度來說,讀寫分離雖然從邏輯表結(jié)構(gòu)角度來說是相同的,都具有相同的字段定義,但是物理實(shí)現(xiàn)上是一定是不相同(要是完全相同,說明沒有領(lǐng)會(huì)讀寫分離的初衷)的,尤其是在索引上,寫庫可能除了PK、唯一索引(任何表都應(yīng)該有唯一索引,分布式鎖只能作為緩沖器)外,最多還有一兩個(gè)簡(jiǎn)單的字段索引以最大化性能,任何SQL符合條件的數(shù)據(jù)一般不會(huì)超過幾十條(極端客戶除外),但是讀庫根據(jù)業(yè)務(wù)不同,可能會(huì)有很多的索引以滿足各種查詢以及簡(jiǎn)單的統(tǒng)計(jì)匯總報(bào)表的需求。

那寫庫是不是一定就比讀庫重要呢?是,又不是。是是絕對(duì)的,不是是相對(duì)的。因?yàn)樽x庫不是DSS庫,是交易庫中相對(duì)來說不是特別重要的業(yè)務(wù)功能。所以,寫庫一旦掛了,就會(huì)導(dǎo)致業(yè)務(wù)下不去,讀庫掛了,可能會(huì)導(dǎo)致做業(yè)務(wù)的人決策錯(cuò)誤。比如沒有沒有查到做過某交易,又重新交易一次。

考慮分庫分表一個(gè)很重要的決策就是是否允許跨多庫操作以及有沒有必要。TODO。。。。待補(bǔ)充。。。。。。

其次,分庫和分表是兩件事,是到底選擇分庫還是分表,如果量沒有那么大的話而且是虛擬機(jī)的話,估計(jì)分庫就夠了。

sharding-jdbc的版本及其架構(gòu)差異

目前最新版本的sharding-jdbc是v3.0.0.M1,應(yīng)該來說還不穩(wěn)定,包名又改成了io.shardingsphere,jar包名是sharding-jdbc。

1.5.4.1是目前最新版,也可能是終版,1.x的,坐標(biāo)是com.dangdang,jar包名是sharding-jdbc。

2.0.3是目前最新版,包名和坐標(biāo)統(tǒng)一改成了io.shardingjdbc,jar包名是sharding-jdbc-core。

說明規(guī)劃不是特別好,還是有些亂。

因?yàn)?.0之后基本上純粹分庫分表的核心特性的增強(qiáng)就不多了,主要往治理和代理方向去了,所以如果沒有特別的需求比如需要類似mycat的獨(dú)立服務(wù)代理模式,使用1.x(注:1.x版本官網(wǎng)文檔好像下線了)就可以了,不過如果是大規(guī)模的部署,同時(shí)已經(jīng)使用了微服務(wù)架構(gòu)中的注冊(cè)中心或者基于spring boot,可以考慮使用2.0,因?yàn)?.0增加了基于注冊(cè)中心的配置管理以及spring boot starter。所以2.0的架構(gòu)是這樣的:

3.0之后,增加了類似mycat角色的sharding-proxy無狀態(tài)服務(wù)器(代理層可以有,但是不應(yīng)該作為應(yīng)用直接訪問的入口,如下圖所示),以及類似于Service Mesh的Database Mesh。不過核心沒有變化,對(duì)SQL語法增加了部分新的支持。所以3.0的架構(gòu)如下:

?

?就分庫分表核心來說,我們就只要關(guān)心sharding-jdbc就可以了,不需要關(guān)心sharding-sphere的其他部分。

sharding-jdbc/Sharding-Proxy/Sharding-Sidecar三者的對(duì)比如下:

?

核心特性

事務(wù)

對(duì)任何重要的系統(tǒng)來說,事務(wù)一致性都是關(guān)鍵的。對(duì)分布式系統(tǒng)來說更是如此,最重要的就是事務(wù)一致性,從這個(gè)層面來說,分庫分表本身并沒有引入另外一個(gè)層次的復(fù)雜性。因?yàn)樗趈dbc驅(qū)動(dòng)層包了一層,所以我們有必要理解它對(duì)事務(wù)的支持性以及相關(guān)的限制。事務(wù)

sharding jdbc 2.x不支持強(qiáng)一致性的分布式事務(wù),一般現(xiàn)在的系統(tǒng)設(shè)計(jì)也不追求強(qiáng)一致性,而是最終一致性。所以sharding jdbc 2.x支持2中事務(wù):弱XA(同mycat)和最大努力投遞事務(wù)(官方簡(jiǎn)稱BED)(算是BASE的一種),具體選擇哪一種需要根據(jù)業(yè)務(wù)和開發(fā)進(jìn)行權(quán)衡,如果架構(gòu)規(guī)范和設(shè)計(jì)做得好,是可以做到不跨庫分布式事務(wù)的。

弱XA事務(wù)是默認(rèn)的模式(即只要dml期間沒有拋出異常,commit期間有機(jī)器斷網(wǎng)或者宕機(jī),是無法保證一致性的),沒有特別的要求。

BED則在一定上增加了短時(shí)容忍,將執(zhí)行的語句另作中心化存儲(chǔ),然后輪詢commit期間失敗的事務(wù)重試,所以BED的架構(gòu)如下:

?

但是沒有免費(fèi)的午餐,BED對(duì)開發(fā)和維護(hù)有著一定的額外要求,而且這些要求都涉及面很廣,絕對(duì)算得上傷筋動(dòng)骨。開發(fā)層面包括:

  • INSERT語句的主鍵不能自增
  • UPDATE必須可重復(fù)執(zhí)行,比如不支持UPDATE xxx SET x=x+1,對(duì)于更新余額類,這就相當(dāng)于要求必須樂觀鎖了
  • 運(yùn)維層面包括:

  • 需要存儲(chǔ)事務(wù)日志的數(shù)據(jù)庫
  • 用于異步作業(yè)使用的zookeeper
  • 解壓sharding-jdbc-transaction-async-job-$VERSION.tar,通過start.sh腳本啟動(dòng)異步作業(yè)
  • 我們選擇了從設(shè)計(jì)層面避免強(qiáng)一致性的分布式事務(wù)。

    分片靈活性

    對(duì)于分庫分表來說,很重要的一個(gè)特性是分片的靈活性,比如單個(gè)字段、多個(gè)字段的=、IN、>=、<=。為什么多個(gè)字段很重要的,這里涉及到一個(gè)特殊的考慮

    sharding-jdbc目前提供4種分片算法。

    由于分片算法和業(yè)務(wù)實(shí)現(xiàn)緊密相關(guān),因此并未提供內(nèi)置分片算法,而是通過分片策略將各種場(chǎng)景提煉出來,提供更高層級(jí)的抽象,并提供接口讓應(yīng)用開發(fā)者自行實(shí)現(xiàn)分片算法。

    • 精確分片算法

    對(duì)應(yīng)PreciseShardingAlgorithm,用于處理使用單一鍵作為分片鍵的=與IN進(jìn)行分片的場(chǎng)景。需要配合StandardShardingStrategy使用。

    • 范圍分片算法

    對(duì)應(yīng)RangeShardingAlgorithm,用于處理使用單一鍵作為分片鍵的BETWEEN AND進(jìn)行分片的場(chǎng)景。需要配合StandardShardingStrategy使用。

    • 復(fù)合分片算法

    對(duì)應(yīng)ComplexKeysShardingAlgorithm,用于處理使用多鍵作為分片鍵進(jìn)行分片的場(chǎng)景,多分片鍵邏輯較復(fù)雜,需要應(yīng)用開發(fā)者自行處理其中的復(fù)雜度。需要配合ComplexShardingStrategy使用。

    • Hint分片算法(Hint分片指的是對(duì)于分片字段非SQL決定,而由其他外置條件決定的場(chǎng)景,可使用SQL Hint靈活的注入分片字段。例:內(nèi)部系統(tǒng),按照員工登錄ID分庫,而數(shù)據(jù)庫中并無此字段。SQL Hint支持通過Java API和SQL注釋(待實(shí)現(xiàn))兩種方式使用。)

    對(duì)應(yīng)HintShardingAlgorithm,用于處理使用Hint行分片的場(chǎng)景。需要配合HintShardingStrategy使用。

    因?yàn)樗惴ǖ撵`活性,標(biāo)準(zhǔn)的方式是通過實(shí)現(xiàn)具體的java接口是實(shí)現(xiàn)具體的分片算法比如SingleKeyDatabaseShardingAlgorithm,有不少的情況下,分片是比較簡(jiǎn)單的,比如說純粹是客戶編號(hào),此時(shí)提供了行內(nèi)表達(dá)式分片策略,使用Groovy的表達(dá)式,提供對(duì)SQL語句中的=和IN的分片操作支持,不過這只支持單分片鍵。比如,t_user_${u_id % 8}?表示t_user表按照u_id按8取模分成8個(gè)表,表名稱為t_user_0到t_user_7。

    分片鍵+分片算法=真正可用的分片策略。

    算法和分片鍵的選擇是分庫分表的關(guān)鍵,其直接決定了各個(gè)分庫的負(fù)載是否均衡,以及擴(kuò)展是否容易。在設(shè)計(jì)上的考慮一節(jié)筆者會(huì)詳細(xì)闡述,訂單和委托業(yè)務(wù)、用戶在使用分庫分表時(shí)設(shè)計(jì)上的考慮以及原因。?

    SQL語法限制

    對(duì)于分庫分表來說,還需要知道有哪些SQL的限制,尤其是涉及到需要二次處理的,比如排序,去重,聚合等。

    這里筆者就列下那些常用但沒有被支持的。比如:

    • case when
    • distinct
    • union

    不過好在這些在java/js中處理都比較方便。

    如果有很復(fù)雜的SQL,那最大的可能就是設(shè)計(jì)上有問題,應(yīng)該采用讀寫分離解決。

    sharding-jdbc對(duì)SQL的限制完整可以參考http://shardingsphere.io/document/current/cn/features/sharding/usage-standard/sql/

    設(shè)計(jì)上的考慮

    哪些表要分庫分表

    首先從設(shè)計(jì)上要區(qū)分清楚哪些是廣播表/哪些是分庫表/哪些是只在一個(gè)庫的全局表,因?yàn)槭枪脭?shù)據(jù)源的,所以不管是不是分庫的表,都需要配置,不配置分片規(guī)則Sharding-JDB即無法精確的斷定應(yīng)該路由至哪個(gè)數(shù)據(jù)源。但是一般分庫分表組件包括Sharding-JDBC都會(huì)提供簡(jiǎn)化配置的方法。對(duì)于不分片的表:

    方法1:sharding-jdbc可以在<sharding:sharding-rule />配置default-data-source-name,這樣未配置分片規(guī)則的表將通過默認(rèn)數(shù)據(jù)源定位。

    方法2:將不參與分庫分表的數(shù)據(jù)源獨(dú)立于Sharding-JDBC之外,在應(yīng)用中使用多個(gè)數(shù)據(jù)源分別處理分片和不分片的情況。

    分庫還是分表

    一般來說應(yīng)該選擇分庫(準(zhǔn)確的說是分schema),不應(yīng)該使用分表, 因?yàn)閛racle可以包含n個(gè)schema,mysql可以包含多個(gè)database,而且就算真的需要,schema之間也是可以關(guān)聯(lián)查詢的,所以感覺就算是為了擴(kuò)展性問題,也沒有必要使用分表,分表反而在擴(kuò)展的時(shí)候更加麻煩。就算數(shù)據(jù)量多了一點(diǎn),感覺稍微偏慢,可以先采用分區(qū)擋一擋。

    分片鍵的選擇

    ?其中最重要的是分片鍵不能是自增字段,否則insert就不知道去哪里了。所以對(duì)于ID生成,需要一個(gè)ID生成中心。

    分布式主鍵

    分布式系統(tǒng)的主鍵生成可以通過設(shè)置增量或者也通過ID生成中心來生成,不過話說回來,既然使用ID生成中心了,就不要再使用數(shù)據(jù)庫機(jī)制的ID了,這不一定需要通過代碼全部重寫,可以在dao層通過aop判斷是否insert,是Insert的動(dòng)態(tài)從ID中心獲取,這樣就避免了分庫分表和非分庫分表在開發(fā)商的差別。?

    Sharding-JDBC使用說明

    對(duì)于只有一個(gè)分片鍵的使用=和IN進(jìn)行分片的SQL,建議使用行表達(dá)式代替Java類的配置。假設(shè)我們不使用弱性事務(wù)(如果使用柔性事務(wù),則還需要引入sharding-jdbc-transaction以及sharding-jdbc-transaction-async-job),這樣就只要引入sharding-jdbc-core這個(gè)jar包就可以了,(因?yàn)閟harding-jdbc的配置支持java、yaml、spring boot以及spring命名空間(類似dubbo),所以建議使用spring 命名空間方式)如下:

    <dependency><groupId>io.shardingjdbc</groupId><artifactId>sharding-jdbc-core</artifactId><version>2.0.3</version></dependency><!-- for sharding-jdbc spring namespace --><dependency><groupId>io.shardingjdbc</groupId><artifactId>sharding-jdbc-core-spring-namespace</artifactId><version>2.0.3</version></dependency>

    因?yàn)閟harding jdbc可以支持dbcp、druid,所以就不用改動(dòng)其他的依賴項(xiàng)了。

    接下去配置數(shù)據(jù)源、數(shù)據(jù)源分片策略和表分片策略。

    我們假設(shè)分庫結(jié)構(gòu)(此處2個(gè)庫僅做演示目的,實(shí)際應(yīng)該至少4個(gè)分庫)如下:

    order和order_item通過order_id關(guān)聯(lián),且分片規(guī)則相同。

    分庫1和分庫2通過user_id作為分片字段,采用取模(采用取模而不是區(qū)間的好處是負(fù)載從理論上最均衡,用區(qū)間其實(shí)是不均衡的,比如假設(shè)客戶比較穩(wěn)定,就1000萬,0-100萬第一個(gè)分片,以此類推,實(shí)際上還是可能很不均衡,因?yàn)槟扯螘r(shí)間增加的客戶可能會(huì)特別活躍,尤其是在互聯(lián)網(wǎng)應(yīng)用中)

    配置三個(gè)數(shù)據(jù)源:

    1、globalDataSource,指向全局庫,非分庫分表和廣播的表,比如系統(tǒng)參數(shù);

    2、dataSource_0、dataSource_1,指向分庫1和分庫2;

    <bean name="dataSource_0" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><property name="url" value="${jdbc.url_0}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/><!-- 配置初始化大小、最小、最大 --><property name="initialSize" value="${jdbc.initialSize}"/><property name="minIdle" value="${jdbc.minIdle}"/><property name="maxActive" value="${jdbc.maxActive}"/><!-- 配置獲取連接等待超時(shí)的時(shí)間 --><property name="maxWait" value="${jdbc.maxWait}"/><!-- 打開PSCache,并且指定每個(gè)連接上PSCache的大小 --><property name="poolPreparedStatements" value="${jdbc.pps}"/><property name="maxPoolPreparedStatementPerConnectionSize" value="${jdbc.mpps}"/><!-- 配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒 --><property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/><!-- 配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒 --><property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/><property name="removeAbandoned" value="${jdbc.removeAbandoned}"/><property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}"/><property name="logAbandoned" value="${jdbc.logAbandoned}"/><!-- 配置監(jiān)控統(tǒng)計(jì)攔截的filters --><property name="filters" value="${jdbc.filters}"/></bean><bean name="dataSource_1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><property name="url" value="${jdbc.url_1}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/><!-- 配置初始化大小、最小、最大 --><property name="initialSize" value="${jdbc.initialSize}"/><property name="minIdle" value="${jdbc.minIdle}"/><property name="maxActive" value="${jdbc.maxActive}"/><!-- 配置獲取連接等待超時(shí)的時(shí)間 --><property name="maxWait" value="${jdbc.maxWait}"/><!-- 打開PSCache,并且指定每個(gè)連接上PSCache的大小 --><property name="poolPreparedStatements" value="${jdbc.pps}"/><property name="maxPoolPreparedStatementPerConnectionSize" value="${jdbc.mpps}"/><!-- 配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒 --><property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/><!-- 配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒 --><property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/><property name="removeAbandoned" value="${jdbc.removeAbandoned}"/><property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}"/><property name="logAbandoned" value="${jdbc.logAbandoned}"/><!-- 配置監(jiān)控統(tǒng)計(jì)攔截的filters --><property name="filters" value="${jdbc.filters}"/></bean><bean name="globalDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/><!-- 配置初始化大小、最小、最大 --><property name="initialSize" value="${jdbc.initialSize}"/><property name="minIdle" value="${jdbc.minIdle}"/><property name="maxActive" value="${jdbc.maxActive}"/><!-- 配置獲取連接等待超時(shí)的時(shí)間 --><property name="maxWait" value="${jdbc.maxWait}"/><!-- 打開PSCache,并且指定每個(gè)連接上PSCache的大小 --><property name="poolPreparedStatements" value="${jdbc.pps}"/><property name="maxPoolPreparedStatementPerConnectionSize" value="${jdbc.mpps}"/><!-- 配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒 --><property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/><!-- 配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒 --><property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/><property name="removeAbandoned" value="${jdbc.removeAbandoned}"/><property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}"/><property name="logAbandoned" value="${jdbc.logAbandoned}"/><!-- 配置監(jiān)控統(tǒng)計(jì)攔截的filters --><property name="filters" value="${jdbc.filters}"/></bean>

    ?

    全局表、分庫不分表、分庫分表、廣播表、主、子表綁定的各自規(guī)則配置(下面使用行內(nèi)策略,注:https://blog.csdn.net/shijiemozujiejie/article/details/80786231提到行表達(dá)式的策略不利于數(shù)據(jù)庫和表的橫向擴(kuò)展,這是有道理的,因?yàn)閖ava代碼我們可以隨時(shí)重新加載分庫和分表的基數(shù),做到不停機(jī)擴(kuò)展,但是行內(nèi)表達(dá)式不行)如下:

    <!-- 分庫策略 --><sharding:inline-strategy id="databaseStrategy" sharding-column="user_id" algorithm-expression="dataSource_${user_id % 2}" /><!-- 分表策略 --><sharding:inline-strategy id="orderTableStrategy" sharding-column="order_id" algorithm-expression="t_order_${order_id % 2}" /><sharding:inline-strategy id="orderItemTableStrategy" sharding-column="order_id" algorithm-expression="t_order_item_${order_id % 2}" /><sharding:data-source id="shardingDataSource"><!-- configDataSource為不參數(shù)分庫分表的全局表的默認(rèn)數(shù)據(jù)源,比如系統(tǒng)參數(shù) --><sharding:sharding-rule data-source-names="dataSource_0,dataSource_1,globalDataSource" default-data-source-name="globalDataSource"><sharding:table-rules><!-- 分庫+分表 --><sharding:table-rule logic-table="t_order" actual-data-nodes="dataSource_${0..1}.t_order_${0..1}" database-strategy-ref="databaseStrategy" table-strategy-ref="orderTableStrategy" /><sharding:table-rule logic-table="t_order_item" actual-data-nodes="dataSource_${0..1}.t_order_item_${0..1}" database-strategy-ref="databaseStrategy" table-strategy-ref="orderItemTableStrategy" />
      
              <!-- 分庫不分表 --><sharding:table-rule logic-table="t_order" database-strategy-ref="databaseStrategy"/><!-- 廣播表 --><sharding:table-rule logic-table="t_dict"/></sharding:table-rules><!-- 綁定表規(guī)則列表,表示分庫分表的規(guī)則相同,這樣萬一涉及到多個(gè)分片的查詢,sharding-jdbc就可以確定分庫之間不需要不必要的二次關(guān)聯(lián),所有的查詢都應(yīng)該如此 --><sharding:binding-table-rules><sharding:binding-table-rule logic-tables="t_order,t_order_item"/></sharding:binding-table-rules></sharding:sharding-rule></sharding:data-source><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="shardingDataSource" /></bean><!-- 使用annotation 自動(dòng)注冊(cè)bean, 并保證@Required、@Autowired的屬性被注入 --><tx:annotation-driven transaction-manager="transactionManager"/><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="configLocation" value="classpath:mybatis.xml"/><property name="dataSource" ref="shardingDataSource"/><property name="mapperLocations"><list><value>classpath*:sqlmap/com/yidoo/k3c/**/*.xml</value></list></property></bean>

    ?

    HINT分片策略的使用

    Hint分片指的是對(duì)于分片字段非SQL決定,而由其他外置條件決定的場(chǎng)景,可使用SQL Hint靈活的注入分片字段。舉個(gè)實(shí)例的例子,我們都知道m(xù)ysql insert values相對(duì)于循環(huán)插入來說,性能差距基本上可以說是網(wǎng)絡(luò)延時(shí)的倍數(shù),比如說插入1000條記錄,網(wǎng)絡(luò)來回1ms,1000條就得1m,如果是跨網(wǎng)段的,延時(shí)就更長(zhǎng)了。而sharding-jdbc和Mycat都不支持多values(sharding-jdbc 3.x支持,但還沒有正式發(fā)布),有些SQL語句比較復(fù)雜比如說有(a = var or b = var) and member_id = N,這個(gè)時(shí)候druid sqlparser并不支持的時(shí)候,雖然可以通過多數(shù)據(jù)源解決,但是我們不希望架構(gòu)搞得太復(fù)雜,這種情況下,可以通過sharding-jdbc的Hint分片策略來實(shí)現(xiàn)各種sharding-jdbc不支持的語法的限制。因?yàn)镠int分片策略是繞過SQL解析的,所以對(duì)于這些比較復(fù)雜的需要分片的非DSS查詢,采用Hint分片策略性能可能會(huì)更好。同樣,我們還是使用mybatis作為數(shù)據(jù)庫訪問層作為例子,對(duì)于Hint分片策略,帖子大都是基于1.x版本進(jìn)行源碼分析路由,順帶提及,基本上都是瞎扯,同時(shí)在用法上sharding-jdbc-example沒有提及。因?yàn)槲覀儗?shí)際要用,所以筆者基于2.0.3版本進(jìn)行了完整的測(cè)試確保結(jié)果符合我們的預(yù)期。

    首先定義一個(gè)hint策略,hint策略需要實(shí)現(xiàn)io.shardingjdbc.core.api.algorithm.sharding.hint.HintShardingAlgorithm接口。

    <sharding:hint-strategy id="hintDatabaseStrategy" algorithm-class="com.yidoo.common.route.hint.HintShardingAlgorithm"/> package com.yidoo.common.route.hint;import java.util.ArrayList; import java.util.Collection; import java.util.List;import org.slf4j.Logger; import org.slf4j.LoggerFactory;import com.alibaba.druid.util.StringUtils; import com.yidoo.utils.JacksonHelper;import io.shardingjdbc.core.api.algorithm.sharding.ListShardingValue; import io.shardingjdbc.core.api.algorithm.sharding.ShardingValue;public class HintShardingAlgorithm implements io.shardingjdbc.core.api.algorithm.sharding.hint.HintShardingAlgorithm {private static final Logger logger = LoggerFactory.getLogger(HintShardingAlgorithm.class);@Overridepublic Collection<String> doSharding(Collection<String> availableTargetNames, ShardingValue shardingValue) {logger.debug("shardingValue=" + JacksonHelper.toJSON(shardingValue));logger.debug("availableTargetNames=" + JacksonHelper.toJSON(availableTargetNames));List<String> shardingResult = new ArrayList<>();availableTargetNames.forEach(targetName -> {String suffix = targetName.substring(targetName.lastIndexOf("_")+1);if(StringUtils.isNumber(suffix)) {
    // hint分片算法的ShardingValue有兩種具體類型: ListShardingValue和RangeShardingValue,取決于io.shardingjdbc.core.api.HintManager.addDatabaseShardingValue(String, String, ShardingOperator, Comparable<?>...)的時(shí)候,ShardingOperator的類型。見下文。ListShardingValue
    <Integer> tmpSharding = (ListShardingValue<Integer>) shardingValue; tmpSharding.getValues().forEach(value -> {if (value % 2 == Integer.parseInt(suffix)) {shardingResult.add(targetName);}});}});return shardingResult;}} @SuppressWarnings("unchecked")private ShardingValue getShardingValue(final String logicTable, final String shardingColumn, final ShardingOperator operator, final Comparable<?>[] values) {Preconditions.checkArgument(null != values && values.length > 0);switch (operator) {case EQUAL:case IN:return new ListShardingValue(logicTable, shardingColumn, Arrays.asList(values));case BETWEEN:return new RangeShardingValue(logicTable, shardingColumn, Range.range(values[0], BoundType.CLOSED, values[1], BoundType.CLOSED));default:throw new UnsupportedOperationException(operator.getExpression());}}

    sharding:sharding-rule節(jié)點(diǎn)上定義屬性default-database-strategy-ref為hintDatabaseStrategy,如下:

    <sharding:sharding-rule data-source-names="dataSource_0,dataSource_1,globalDataSource" default-database-strategy-ref="hintDatabaseStrategy" default-data-source-name="globalDataSource">

    不用定義<sharding:table-rules>。

    接下去在執(zhí)行sql語句前設(shè)置分片值即可,如下:

    UnitQuery treq = new UnitQuery();Unit record1 = new Unit();record1.setUnitName("強(qiáng)制指定Hint-1");record1.setRemark1(" ");record1.setInputMan("系統(tǒng)管理員");Unit record2 = new Unit();record2.setUnitName("強(qiáng)制指定Hint-3");record2.setRemark1(" ");record2.setInputMan("系統(tǒng)管理員");List<Unit> records = new ArrayList<>();records.add(record1);records.add(record2);HintManager hintManager = HintManager.getInstance();hintManager.setDatabaseShardingValue(1); // hintManager.addDatabaseShardingValue("t_Unit","user_id",1); unitMapper.insertValues(records);hintManager.close();hintManager = HintManager.getInstance(); // 必須先clear,重新拿到instancehintManager.setDatabaseShardingValue(1);List<Unit> unitList = unitMapper.selectByHint(treq);logger.info("強(qiáng)制指定Hint-1提示" + JacksonHelper.toJSON(unitList));hintManager.close();Unit record3 = new Unit();record3.setUnitName("強(qiáng)制指定Hint-2");record3.setRemark1(" ");record3.setInputMan("系統(tǒng)管理員");Unit record4 = new Unit();record4.setUnitName("強(qiáng)制指定Hint-4");record4.setRemark1(" ");record4.setInputMan("系統(tǒng)管理員");records.clear();records.add(record3);records.add(record4);hintManager = HintManager.getInstance();hintManager.setDatabaseShardingValue(2); // hintManager.addDatabaseShardingValue("t_Unit","user_id",2); unitMapper.insertValues(records);hintManager.close();hintManager = HintManager.getInstance();unitList = unitMapper.selectByHint(treq);logger.info("強(qiáng)制指定Hint-2提示" + JacksonHelper.toJSON(unitList));hintManager.close();

    mapper中如下:

    <insert id="insertValues">insert into t_Unit(unit_name,remark1,input_man,input_date) values<foreach collection="list" item="item" index="index" separator=",">(#{item.unitName},#{item.remark1},#{item.inputMan},now())</foreach></insert><select id="selectByHint" resultType="com.yidoo.k3c.global.model.pojo.Unit">select * from t_Unit</select>

    執(zhí)行前:

    執(zhí)行后:

    ?

    日志:

    ?

    [] 2018-07-05 10:10:21 [61125] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) Logic SQL: insert into t_Unit(unit_name,remark1,input_man,input_date) values(?,?,?,now()), (?,?,?,now()) [] 2018-07-05 10:10:21 [61125] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) SQLStatement: DMLStatement(super=AbstractSQLStatement(type=DML, tables=Tables(tables=[]), conditions=Conditions(conditions={}), sqlTokens=[], parametersIndex=0)) [] 2018-07-05 10:10:21 [61125] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) Actual SQL: dataSource_1 ::: insert into t_Unit(unit_name,remark1,input_man,input_date) values(?,?,?,now()), (?,?,?,now()) ::: [強(qiáng)制指定Hint-1, , 系統(tǒng)管理員, 強(qiáng)制指定Hint-3, , 系統(tǒng)管理員] [] 2018-07-05 10:10:21 [61514] [c.a.d.p.PreparedStatementPool]-[DEBUG] localhost-startStop-1 com.alibaba.druid.pool.PreparedStatementPool.put(PreparedStatementPool.java:129) {conn-110005, pstmt-120000} enter cache [] 2018-07-05 10:10:21 [61515] [o.m.s.SqlSessionUtils]-[DEBUG] localhost-startStop-1 org.mybatis.spring.SqlSessionUtils.closeSqlSession(SqlSessionUtils.java:168) Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b3a6ec5] [] 2018-07-05 10:10:21 [61515] [o.s.j.d.DataSourceUtils]-[DEBUG] localhost-startStop-1 org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:329) Returning JDBC Connection to DataSource [] 2018-07-05 10:10:21 [61519] [o.m.s.SqlSessionUtils]-[DEBUG] localhost-startStop-1 org.mybatis.spring.SqlSessionUtils.getSqlSession(SqlSessionUtils.java:104) Creating a new SqlSession [] 2018-07-05 10:10:21 [61519] [o.m.s.SqlSessionUtils]-[DEBUG] localhost-startStop-1 org.mybatis.spring.SqlSessionUtils.getSqlSession(SqlSessionUtils.java:140) SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@41aefec2] was not registered for synchronization because synchronization is not active [] 2018-07-05 10:10:21 [61523] [o.s.j.d.DataSourceUtils]-[DEBUG] localhost-startStop-1 org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:110) Fetching JDBC Connection from DataSource [] 2018-07-05 10:10:21 [61523] [o.m.s.t.SpringManagedTransaction]-[DEBUG] localhost-startStop-1 org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction.java:86) JDBC Connection [io.shardingjdbc.core.jdbc.core.connection.ShardingConnection@5e996b5d] will not be managed by Spring [] 2018-07-05 10:10:21 [61528] [i.s.c.r.t.h.DatabaseHintRoutingEngine]-[DEBUG] localhost-startStop-1 io.shardingjdbc.core.routing.type.hint.DatabaseHintRoutingEngine.route(DatabaseHintRoutingEngine.java:55) Before database sharding only db:[dataSource_0, dataSource_1, globalDataSource] sharding values: ListShardingValue(logicTableName=DB_TABLE_NAME, columnName=DB_COLUMN_NAME, values=[1]) [] 2018-07-05 10:10:21 [61529] [i.s.c.r.t.h.DatabaseHintRoutingEngine]-[DEBUG] localhost-startStop-1 io.shardingjdbc.core.routing.type.hint.DatabaseHintRoutingEngine.route(DatabaseHintRoutingEngine.java:59) After database sharding only result: [dataSource_1] [] 2018-07-05 10:10:21 [61530] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) Logic SQL: select * from t_Unit [] 2018-07-05 10:10:21 [61530] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) SQLStatement: SelectStatement(super=DQLStatement(super=AbstractSQLStatement(type=DQL, tables=Tables(tables=[]), conditions=Conditions(conditions={}), sqlTokens=[], parametersIndex=0)), containStar=false, selectListLastPosition=0, groupByLastPosition=0, items=[], groupByItems=[], orderByItems=[], limit=null, subQueryStatement=null) [] 2018-07-05 10:10:21 [61530] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) Actual SQL: dataSource_1 ::: select * from t_Unit [] 2018-07-05 10:10:21 [61576] [c.a.d.p.PreparedStatementPool]-[DEBUG] localhost-startStop-1 com.alibaba.druid.pool.PreparedStatementPool.put(PreparedStatementPool.java:129) {conn-110005, pstmt-120001} enter cache [] 2018-07-05 10:10:21 [61577] [o.m.s.SqlSessionUtils]-[DEBUG] localhost-startStop-1 org.mybatis.spring.SqlSessionUtils.closeSqlSession(SqlSessionUtils.java:168) Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@41aefec2] [] 2018-07-05 10:10:21 [61578] [o.s.j.d.DataSourceUtils]-[DEBUG] localhost-startStop-1 org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:329) Returning JDBC Connection to DataSource [] 2018-07-05 10:10:21 [61582] [c.y.c.s.ParamexService]-[INFO] localhost-startStop-1 com.yidoo.common.service.ParamexService.afterPropertiesSet(ParamexService.java:79) 強(qiáng)制指定Hint-1提示[{"unitName":"體積","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000},{"unitName":"容量","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000},{"unitName":"廣播","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1529984218000,"updateMan":null,"updateDate":1529984218000},{"unitName":"強(qiáng)制指定Hint-1","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1530756621000,"updateMan":null,"updateDate":1530756621000},{"unitName":"強(qiáng)制指定Hint-3","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1530756621000,"updateMan":null,"updateDate":1530756621000},{"unitName":"數(shù)量","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000},{"unitName":"重量","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000},{"unitName":"長(zhǎng)度","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000},{"unitName":"面積","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000}] [] 2018-07-05 10:10:21 [61585] [i.s.c.r.t.h.DatabaseHintRoutingEngine]-[DEBUG] localhost-startStop-1 io.shardingjdbc.core.routing.type.hint.DatabaseHintRoutingEngine.route(DatabaseHintRoutingEngine.java:55) Before database sharding only db:[dataSource_0, dataSource_1, globalDataSource] sharding values: ListShardingValue(logicTableName=DB_TABLE_NAME, columnName=DB_COLUMN_NAME, values=[2]) [] 2018-07-05 10:10:21 [61586] [i.s.c.r.t.h.DatabaseHintRoutingEngine]-[DEBUG] localhost-startStop-1 io.shardingjdbc.core.routing.type.hint.DatabaseHintRoutingEngine.route(DatabaseHintRoutingEngine.java:59) After database sharding only result: [dataSource_0] [] 2018-07-05 10:10:21 [61587] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) Logic SQL: insert into t_Unit(unit_name,remark1,input_man,input_date) values(?,?,?,now()), (?,?,?,now()) [] 2018-07-05 10:10:21 [61587] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) SQLStatement: DMLStatement(super=AbstractSQLStatement(type=DML, tables=Tables(tables=[]), conditions=Conditions(conditions={}), sqlTokens=[], parametersIndex=0)) [] 2018-07-05 10:10:21 [61587] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) Actual SQL: dataSource_0 ::: insert into t_Unit(unit_name,remark1,input_man,input_date) values(?,?,?,now()), (?,?,?,now()) ::: [強(qiáng)制指定Hint-2, , 系統(tǒng)管理員, 強(qiáng)制指定Hint-4, , 系統(tǒng)管理員] [] 2018-07-05 10:10:21 [61624] [c.a.d.p.PreparedStatementPool]-[DEBUG] localhost-startStop-1 com.alibaba.druid.pool.PreparedStatementPool.put(PreparedStatementPool.java:129) {conn-10005, pstmt-20000} enter cache [] 2018-07-05 10:10:21 [61625] [o.m.s.SqlSessionUtils]-[DEBUG] localhost-startStop-1 org.mybatis.spring.SqlSessionUtils.closeSqlSession(SqlSessionUtils.java:168) Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@767f7324] [] 2018-07-05 10:10:21 [61625] [o.s.j.d.DataSourceUtils]-[DEBUG] localhost-startStop-1 org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:329) Returning JDBC Connection to DataSource [] 2018-07-05 10:10:21 [61625] [o.m.s.SqlSessionUtils]-[DEBUG] localhost-startStop-1 org.mybatis.spring.SqlSessionUtils.getSqlSession(SqlSessionUtils.java:104) Creating a new SqlSession [] 2018-07-05 10:10:21 [61626] [o.m.s.SqlSessionUtils]-[DEBUG] localhost-startStop-1 org.mybatis.spring.SqlSessionUtils.getSqlSession(SqlSessionUtils.java:140) SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4c582b4c] was not registered for synchronization because synchronization is not active [] 2018-07-05 10:10:21 [61626] [o.s.j.d.DataSourceUtils]-[DEBUG] localhost-startStop-1 org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:110) Fetching JDBC Connection from DataSource [] 2018-07-05 10:10:21 [61627] [o.m.s.t.SpringManagedTransaction]-[DEBUG] localhost-startStop-1 org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction.java:86) JDBC Connection [io.shardingjdbc.core.jdbc.core.connection.ShardingConnection@b551009] will not be managed by Spring [] 2018-07-05 10:10:21 [61769] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) Logic SQL: select * from t_Unit [] 2018-07-05 10:10:21 [61770] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) SQLStatement: SelectStatement(super=DQLStatement(super=AbstractSQLStatement(type=DQL, tables=Tables(tables=[Table(name=t_Unit, alias=Optional.absent())]), conditions=Conditions(conditions={}), sqlTokens=[TableToken(beginPosition=14, originalLiterals=t_Unit)], parametersIndex=0)), containStar=true, selectListLastPosition=9, groupByLastPosition=0, items=[StarSelectItem(owner=Optional.absent())], groupByItems=[], orderByItems=[], limit=null, subQueryStatement=null) [] 2018-07-05 10:10:21 [61771] [Sharding-JDBC-SQL]-[INFO] localhost-startStop-1 io.shardingjdbc.core.util.SQLLogger.log(SQLLogger.java:59) Actual SQL: globalDataSource ::: select * from t_Unit [] 2018-07-05 10:10:22 [61782] [c.a.d.p.PreparedStatementPool]-[DEBUG] localhost-startStop-1 com.alibaba.druid.pool.PreparedStatementPool.put(PreparedStatementPool.java:129) {conn-210005, pstmt-220000} enter cache [] 2018-07-05 10:10:22 [61782] [o.m.s.SqlSessionUtils]-[DEBUG] localhost-startStop-1 org.mybatis.spring.SqlSessionUtils.closeSqlSession(SqlSessionUtils.java:168) Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4c582b4c] [] 2018-07-05 10:10:22 [61783] [o.s.j.d.DataSourceUtils]-[DEBUG] localhost-startStop-1 org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:329) Returning JDBC Connection to DataSource [] 2018-07-05 10:10:22 [61785] [c.y.c.s.ParamexService]-[INFO] localhost-startStop-1 com.yidoo.common.service.ParamexService.afterPropertiesSet(ParamexService.java:102) 強(qiáng)制指定Hint-2提示[{"unitName":"體積","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000},{"unitName":"容量","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000},{"unitName":"廣播","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1529984218000,"updateMan":null,"updateDate":1529984218000},{"unitName":"強(qiáng)制指定Hint-1","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1530701874000,"updateMan":null,"updateDate":1530701874000},{"unitName":"強(qiáng)制指定Hint-2","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1530701874000,"updateMan":null,"updateDate":1530701874000},{"unitName":"強(qiáng)制指定Hint-3","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1530701874000,"updateMan":null,"updateDate":1530701874000},{"unitName":"強(qiáng)制指定Hint-4","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1530701874000,"updateMan":null,"updateDate":1530701874000},{"unitName":"數(shù)量","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000},{"unitName":"重量","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000},{"unitName":"長(zhǎng)度","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000},{"unitName":"面積","remark1":" ","inputMan":"系統(tǒng)管理員","inputDate":1528166814000,"updateMan":null,"updateDate":1528166814000}]

    ?

    注意點(diǎn)

    1、使用了sharding-jdbc之后,select from TableName會(huì)被轉(zhuǎn)換為select from tablename,也就是轉(zhuǎn)小寫,這是在代碼中處理的,如果不希望轉(zhuǎn)換(sql標(biāo)準(zhǔn)是大小寫不敏感的,主要是mysql linux下lower-case-table-names=1這個(gè)特例會(huì)區(qū)分大小寫,而且mysql 8.0不允許數(shù)據(jù)庫初始化和啟動(dòng)的值不一致,5.7之前是可以的,https://bugs.mysql.com/bug.php?id=90695),則需要自己編譯sharding-jdbc-core(我們編譯了一版sharding-jdbc-core-2.0.3.zip),并更改getTableTokens中的轉(zhuǎn)小寫的代碼(這應(yīng)該算是個(gè)bug),2.0.3版本代碼位置為:

    // io.shardingjdbc.core.rewrite.SQLRewriteEngine.getTableTokens(TableUnit)中對(duì)sql語句中的表名做了toLowerCase()導(dǎo)致的,如下:private Map<String, String> getTableTokens(final TableUnit tableUnit) {String logicTableName = tableUnit.getLogicTableName().toLowerCase();Map<String, String> tableTokens = new HashMap<>();tableTokens.put(logicTableName, tableUnit.getActualTableName());Optional<BindingTableRule> bindingTableRule = shardingRule.findBindingTableRule(logicTableName);if (bindingTableRule.isPresent()) {tableTokens.putAll(getBindingTableTokens(tableUnit, bindingTableRule.get()));}return tableTokens;}

    2、一定要設(shè)置context:property-placeholder的ignore-unresolvable屬性為true,即<context:property-placeholder?location="classpath:property/*.properties"?ignore-unresolvable="true"?/>,否則會(huì)報(bào)無法解析占位符。

    3、我們?cè)谡{(diào)試的時(shí)候遇到個(gè)問題,如果eclipse中同時(shí)把sharding-jdbc的源代碼引入進(jìn)來,war啟動(dòng)的時(shí)候就會(huì)報(bào)sharding.xsd找不到,然后啟動(dòng)出錯(cuò)。

    參考:

    各非行內(nèi)ShardingStrategy的用法可以參考https://www.cnblogs.com/mr-yang-localhost/p/8313360.html

    其他:

    https://wenku.baidu.com/view/ddeaed18910ef12d2bf9e74a.html

    https://www.oschina.net/question/2918182_2280300

    https://www.oschina.net/news/88860/sharding-jdbc-1-5-4-released

    http://www.infoq.com/cn/news/2017/12/Sharding-JDBC-2

    http://cmsblogs.com/?p=2542

    http://shardingjdbc.io/document/legacy/2.x/en/00-overview/

    https://www.oschina.net/question/2356021_2264290?

    https://blog.csdn.net/vkingnew/article/details/80613043

    https://www.jianshu.com/p/dd47dd3b1f6b

    https://www.zhihu.com/question/64709787

    sharding-jdbc不支持SQL

    https://blog.csdn.net/Farrell_zeng/article/details/52958189

    mycat不支持SQL

    https://blog.csdn.net/educast/article/details/50013355

    總結(jié)

    以上是生活随笔為你收集整理的mysql分库分表方案之sharding-jdbc使用(非demo示例)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。