1.Sharding-Jdbc介紹
Sharding-Jdbc在3.0後改名爲ShardingSphere它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(計劃中)這3款相互獨立的產品組成。他們均提供標準化的數據分片、分佈式事務和數據庫治理功能,可適用於如Java同構、異構語言、容器、雲原生等各種多樣化的應用場景。
Sharding-Sphere定位爲關係型數據庫中間件,旨在充分合理地在分佈式的場景下利用關係型數據庫的計算和存儲能力,而並非實現一個全新的關係型數據庫。它通過關注不變,進而抓住事物本質。關係型數據庫當今依然佔有巨大市場,是各個公司核心業務的基石,未來也難於撼動,我們目前階段更加關注在原有基礎上的增量,而非顛覆。
應用場景:
數據庫讀寫分離
數據庫分表分庫
2.Sharding-Jdbc與MyCat區別
MyCat是一個基於第三方應用中間件數據庫代理框架,客戶端所有的jdbc請求都必須要先交給MyCat,再有MyCat轉發到具體的真實服務器中。
Sharding-Jdbc是一個Jar形式,在本地應用層重寫Jdbc原生的方法,實現數據庫分片形式。
MyCat屬於服務器端數據庫中間件,而Sharding-Jdbc是一個本地數據庫中間件框架。
從設計理念上看確實有一定的相似性。主要流程都是SQL 解析 -> SQL 路由 -> SQL 改寫 -> SQL 執行 -> 結果歸併。但架構設計上是不同的。Mycat 是基於 Proxy,它複寫了 MySQL 協議,將 Mycat Server 僞裝成一個 MySQL 數據庫,而 Sharding-JDBC 是基於 JDBC 的擴展,是以 jar 包的形式提供輕量級服務的。
3.Sharding-Jdbc日誌分析與原理圖
1.Sharding-JDBC中的路由結果是通過分片字段和分片方法來確定的,如果查詢條件中有 id 字段的情況還好,查詢將會落到某個具體的分片
2.如果查詢沒有分片的字段,會向所有的db或者是表都會查詢一遍,讓後封裝結果級給客戶端。
Sharding-Jdbc和MyCat查詢原理大致相同
4.Sharding-Jdbc日誌分析與原理圖
一種爲原生配置方式,自己需要實現接口。
1.分庫算法類需要實現SingleKeyDatabaseShardingAlgorithm接口
2.分表算法類需要實現SingleKeyTableShardingAlgorithm接口
第二種通過配置文件形式配置
4.1單庫分表
DataSourceConfig
// 數據源相關配置信息
@Configuration
public class DataSourceConfig {
@Value("${spring.jdbc.db0.className}")
private String className;
@Value("${spring.jdbc.db0.url}")
private String url;
@Value("${spring.jdbc.db0.username}")
private String username;
@Value("${spring.jdbc.db0.password}")
private String password;
@Bean
public IdGenerator getIdGenerator() {
return new CommonSelfIdGenerator();
}
@Bean
public DataSource getDataSource() {
return buildDataSource();
}
private DataSource buildDataSource() {
// 1.設置分庫映射
Map<String, DataSource> dataSourceMap = new HashMap<>(2);
dataSourceMap.put("userdb_1", createDataSource("userdb_1"));
// dataSourceMap.put("ds_1", createDataSource("ds_1"));
// 設置默認db爲ds_0,也就是爲那些沒有配置分庫分表策略的指定的默認庫
// 如果只有一個庫,也就是不需要分庫的話,map裏只放一個映射就行了,只有一個庫時不需要指定默認庫,
// 但2個及以上時必須指定默認庫,否則那些沒有配置策略的表將無法操作數據
DataSourceRule rule = new DataSourceRule(dataSourceMap, "userdb_1");
// 2.設置分表映射,將t_order_0和t_order_1兩個實際的表映射到t_order邏輯表
TableRule orderTableRule = TableRule.builder("t_order").actualTables(Arrays.asList("t_order_0", "t_order_1"))
.dataSourceRule(rule).build();
// 3.具體的分庫分表策略
ShardingRule shardingRule = ShardingRule.builder().dataSourceRule(rule)
.tableRules(Arrays.asList(orderTableRule))
// 根據userid分片字段
.tableShardingStrategy(new TableShardingStrategy("user_id", new TableShardingAlgorithm())).build();
// 創建數據源
DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule);
return dataSource;
}
private DataSource createDataSource(String dataSourceName) {
// 使用druid連接數據庫
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(className);
druidDataSource.setUrl(String.format(url, dataSourceName));
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
TableShardingAlgorithm
/**
* @author Administrator
*/ // 表分片算法
public class TableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Long> {
// sql 中關鍵字 匹配符爲 =的時候,表的路由函數
public String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
for (String tableName : availableTargetNames) {
if (tableName.endsWith(shardingValue.getValue() % 2 + "")) {
return tableName;
}
}
throw new IllegalArgumentException();
}
@Override
public Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
return null;
}
@Override
public Collection<String> doBetweenSharding(Collection<String> availableTargetNames,
ShardingValue<Long> shardingValue) {
return null;
}
}
4.2分庫分表
DataSourceConfig
// 數據源相關配置信息
@Configuration
public class DataSourceConfig {
@Value("${spring.jdbc.db0.className}")
private String className;
@Value("${spring.jdbc.db0.url}")
private String url;
@Value("${spring.jdbc.db0.username}")
private String username;
@Value("${spring.jdbc.db0.password}")
private String password;
@Bean
public IdGenerator getIdGenerator() {
return new CommonSelfIdGenerator();
}
@Bean
public DataSource getDataSource() {
return buildDataSource();
}
private DataSource buildDataSource() {
// 1.設置分庫映射
Map<String, DataSource> dataSourceMap = new HashMap<>(2);
dataSourceMap.put("userdb_0", createDataSource("userdb_0"));
dataSourceMap.put("userdb_1", createDataSource("userdb_1"));
// 設置默認db爲ds_0,也就是爲那些沒有配置分庫分表策略的指定的默認庫
// 如果只有一個庫,也就是不需要分庫的話,map裏只放一個映射就行了,只有一個庫時不需要指定默認庫,
// 但2個及以上時必須指定默認庫,否則那些沒有配置策略的表將無法操作數據
DataSourceRule rule = new DataSourceRule(dataSourceMap, "userdb_1");
// 2.設置分表映射,將t_order_0和t_order_1兩個實際的表映射到t_order邏輯表
TableRule orderTableRule = TableRule.builder("t_order").dataSourceRule(rule).build();
// 3.具體的分庫分表策略
ShardingRule shardingRule = ShardingRule.builder().dataSourceRule(rule)
.tableRules(Arrays.asList(orderTableRule))
.databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new DatabaseShardingAlgorithm()))
.build();
// 創建數據源
DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule);
return dataSource;
}
private DataSource createDataSource(String dataSourceName) {
// 使用druid連接數據庫
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(className);
druidDataSource.setUrl(String.format(url, dataSourceName));
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
DatabaseShardingAlgorithm
public class DatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<Long> {
@Override
public String doEqualSharding(Collection<String> databases, ShardingValue<Long> shardingValue) {
for (String tableName : databases) {
System.out.println("tableName:" + tableName + ",----" + shardingValue.getValue());
if (tableName.endsWith(shardingValue.getValue() % 2 + "")) {
return tableName;
}
}
throw new IllegalArgumentException();
}
@Override
public Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
return null;
}
@Override
public Collection<String> doBetweenSharding(Collection<String> availableTargetNames,
ShardingValue<Long> shardingValue) {
return null;
}
}
4.3配置文件(單庫分表)
spring:
jpa:
show-sql: true
hibernate:
ddl-auto: none
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
sharding:
jdbc:
####ds1
datasource:
names: userdb3
userdb3:
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.223.141:3306/userdb3
username: root
config:
sharding:
tables:
t_order:
table-strategy:
inline:
#### 根據userid 進行分片
sharding-column: user_id
algorithm-expression: userdb3.t_order_$->{user_id % 2}
actual-data-nodes: userdb3.t_order_$->{0..1}
props:
sql:
### 開啓分片日誌
show: true
mybatis:
configuration:
map-underscore-to-camel-case: true
mapperLocations: classpath:mybatis/*.xml
type-aliases-package: com.mayikt.entity