最近在做一些涉及分庫分表的需求,正好周末有點時間就簡單做下總結,也方便自己以后查看。
本文只講述使用Sharding-JDBC做分庫分表的一些實踐經驗,如果有錯誤歡迎大家指出。
什么是Sharding-JDBC
Sharding-jdbc是當當網開源的一款客戶端代理
中間件。Sharding-jdbc包含分庫分片和讀寫分離功能。對應用的代碼沒有侵入型,幾乎沒有任何改動,兼容主流orm框架,主流數據庫連接池。目前屬於Apache的孵化項目ShardingSphere。
Sharding-jdbc定位為輕量級Java框架,在Java的JDBC層提供的額外服務。 它使用客戶端直連數據庫,以jar包形式提供服務,無需額外部署和依賴,可理解為增強版的JDBC驅動,完全兼容JDBC和各種ORM框架。
適用於任何基於JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
支持任何第三方的數據庫連接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
支持任意實現JDBC規范的數據庫。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92標准的數據庫。
官方文檔地址
ShardingSphere:https://shardingsphere.apache.org/
GitHub的地址:https://github.com/apache/incubator-shardingsphere
一些建議和說明
不過我這里建議大家可以簡單過下官方文檔,因為文檔並不全面或者說感覺並不是最新的。
建議大家重點可以放在git上官方的examples
目前官方最新的版本是4.0,如果使用springboot創建,可以使用下面的依賴即可。
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0</version>
</dependency>
Sharding-jdbc功能強大,但是本文重點在於下面幾點,未涉及的地方可以翻閱文檔查看。
1、單庫分表
2、分庫分表(含分庫單表)
3、分表后的查詢
4、分表事務處理
無論上述哪種分庫亦或是分表類型,核心無非是下面幾個配置:
1、配置數據源,明確你有多少個數據源
2、定義表名,分表的邏輯表名(t_order)和所有物理表名(t_order_0,t_order_1)
3、定義分庫列以及分庫算法
4、定義分表列以及分表算法
代碼實現
單庫分表
sharding-jdbc優勢就是對代碼沒有侵入性,基本上不用動我們原來的代碼,只是將相關數據庫連接的配置更換為sharding的配置即可。
以我的個人實踐項目為例:
原來不分表時的配置:
#項目配置
spring:
#數據連接配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://xxx.xx.xx.xx:3306/yyms?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: xxx
password: xxx
使用sharding后的配置
# 分表配置
spring:
shardingsphere:
datasource:
names: yyms
yyms:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://xxx.xx.xx.xx:3306/yyms?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: xx
password: xxx
sharding:
tables:
# 表名
sys_log:
actual-data-nodes: yyms.sys_log_$->{0..1}
# 分表配置,根據id分表
table-strategy:
inline:
sharding-column: id
algorithm-expression: sys_log_$->{id % 2}
# 配置字段的生成策略,column為字段名,type為生成策略,sharding默認提供SNOWFLAKE和UUID兩種,可以自己實現其他策略
key-generator:
column: id
type: SNOWFLAKE
props:
sql:
show: true
上面的配置基本上就實現了單庫對sys_log表的拆分,根據id取模算法,拆分為sys_log_0和sys_log_1兩張表。代碼層面沒有任何改動就實現了拆分,拆分后效果圖如下。
注意哦,sys_log表拆分后是實際不存在的。
當然了,使用官方的默認配置很多時候並不能滿足我們的需求。
假如拿到一條數據的id后再去計算數據在哪個庫,無疑對我們日常的運維維護工作造成極大的不便。這里我們可以通過一些簡單的自定義開發配置實現。
比如我想要id最后一位展示數據所處表所在序號。
多庫分表
先展示個多庫單表的案例
spring:
shardingsphere:
datasource:
names: ds0,ds1
ds_1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://xxxxxx:3306/ds1?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: xxxx
password: xxx
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://xxxxx:3306/ds0?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: xxxx
password: xxxx
sharding:
default-data-source-name: ds0
default-database-strategy:
inline:
sharding-column: id
algorithm-expression: ds$->{id % 2}
tables:
sys_log:
actual-data-nodes: ds$->{0..1}.sys_log
key-generator:
column: id
type: SNOWFLAKE
props:
worker:
id: 123
把單張表拆分到多個庫,同樣使用sys_log。效果圖如下:
其實分庫分表無非就是上面兩種模式的集合,具體配置的選項,可以參考官方案例配置》》》我是鏈接
分庫分表后的查詢
select * from sys_log where id='444271380247588864'
接着上面的案例,以上面的語句為例,id為分庫列,sharding經過解析后定位到對應的數據源,直接執行下面的查詢。
select * from sys_log where id='444271380247588864'
假如我們的查詢調節不包含分庫列,以下面的語句為例:
select * from sys_log where user_name='zhangsan
執行后出現兩條sql語句。我們在兩個庫均為5條數據,查詢后的結果集為10條數據,符合我們的預期。
數據庫:
結果集:
結論:當搜索條件含有分庫列(分表列),這時候sharing會首先調用分庫分表策略類,直接找到對應的數據庫和對應子表。而當搜索條件不含有分庫列時,這時候引擎就不會再調用策略類了,而是會直接認定目標庫為全部庫或表,上述案例中目標庫就是,[ds0,ds1]兩個數據源,既然目標庫有兩個,后面生成的DataNode,TableUnits,PreparedStatementUnit 將是以前數量的兩倍,所以這回,引擎最終將會發起多個sql語句的並發執行,並合並最終的結果再返回。
分庫分表不支持語法注意
https://shardingsphere.apache.org/document/current/cn/features/sharding/use-norms/sql/#不支持項
分庫分表后的事務
Sharding-Sphere同時支持XA和柔性事務,它允許每次對數據庫的訪問,可以自由選擇事務類型。分布式事務對業務操作完全透明,極大地降低了引入分布式事務的成本。
分布式事務我感覺在官方的文檔和案例中寫的已經是比較完善的了,這里大家可以參考:我是鏈接 官方案例實現,這里就不在贅述了。
最后是項目的參考代碼:https://github.com/allanzhuo/yyms