資料庫相關知識脈絡圖
目錄
資料庫相關知識脈絡圖
ShardingSphere簡介
什麼情況下考慮分庫分表呢?
ShardingSphere JDBC基本概念解釋
ShardingSphere JDBC使用
demo位址github
經典三步:
demo介紹:
單庫分表
分庫分表-inline模式-普通不支援範圍查詢
分庫分表-standard模式-範圍查詢
分庫分表-complex模式-混合字段範圍查詢
分庫分表-hint模式-指定資料庫/表
ShardingSphere簡介
官網位址
ShardingSphere是一套開源的分布式資料庫解決方案組成的生态圈,包含:
- ShardingSphere JDBC
- 核心功能:分庫分表 & 讀寫分離
- 引入進我們程式中,提供api去操作分庫分表的jar包。
- 任意jdbc型資料庫都可以使用。
- 侵入性強,也靈活。
- ShardingSphere Proxy
- 隔離在我們程式之外的應用,提供操作分庫分表功能。
- 僅供MySQL,PostgreSQL使用。
- 獨立部署,需提前定義好與資料庫互動的邏輯。
- Sidecar(規劃中)
什麼情況下考慮分庫分表呢?
- 單表資料未來三年超過500萬資料
- 單表資料大小未來三年超過2G
- 根據實際業務
ShardingSphere JDBC基本概念解釋
序号 | 名詞 | 解釋 |
---|---|---|
1 | 邏輯表 | 把一類相同的表、相同增删改查邏輯的表,抽象成一個“邏輯表”,不真實存在。 |
2 | 真實表 | 真實存在的表 |
3 | 廣播表 | 所有庫裡這個表的邏輯字段使用邏輯都相同的表,例如資料字典表要統一。 |
4 | 綁定表 | 像是主表和子表的關系,不可分割,盡量保持一緻的表。 |
5 | 分片鍵 | 例如插入資料時候,根據哪個字段來路由資料進入到各個庫表?那個字段就是分片鍵 |
6 | 分片算法 | 根據什麼算法去路由?取摩運算?直接指定庫名? |
7 | 分片政策 | = 分片鍵 + 分片算法 |
ShardingSphere JDBC使用
demo位址github
https://github.com/lxnxxwl/shardingspheredemo.git
經典三步:
1、 建表:例如mall_order_1 \ mall_order_2..這樣尾數有關聯易表達的。
2、 引入sharding sphere jdbc的依賴
3、 編寫配置檔案
demo介紹:
- maven聚合項目:common包中實體類,其他包為不同配置的分庫分表demo依賴common。
- 使用mybatis plus 進行操作資料庫(測試用例簡單)。mapper在各個demo包中。
- 測試例子在各個demo的test包中。
- 配置檔案采用.properties檔案配置。
單庫分表
- 首先要自己建表(真實表):
- 這裡就是在一個資料庫裡建兩張相同的表mall_order_1 \ mall_order_2。
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for mall_order_1
-- ----------------------------
DROP TABLE IF EXISTS `mall_order_1`;
CREATE TABLE `mall_order_1` (
`id` bigint NOT NULL,
`order_name` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
- 引入pom依賴。
- springboot為例
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
- 編寫配置檔案【單庫分表】
#sharding jdbc 資料庫 起名 m1
spring.shardingsphere.datasource.names=m1
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=root
# 1.哪些節點?==哪幾張表
spring.shardingsphere.sharding.tables.mall_order.actual-data-nodes=m1.mall_order_$->{1..2}
# 2.主鍵是哪一列?
spring.shardingsphere.sharding.tables.mall_order.key-generator.column=cid
# 3.主鍵生成政策是什麼? 可自定義,此處采用已內建的雪花算法
spring.shardingsphere.sharding.tables.mall_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.mall_order.key-generator.props.worker.id=1
# 4.分片鍵:inline模式下按id分表
spring.shardingsphere.sharding.tables.mall_order.table-strategy.inline.sharding-column=cid
# 5.分片算法:ID取摩
spring.shardingsphere.sharding.tables.mall_order.table-strategy.inline.algorithm-expression=mall_order_$->{cid%2+1}
spring.shardingsphere.props.sql.show = true
spring.main.allow-bean-definition-overriding=true
- mapper:
public interface MallOrderMapper extends BaseMapper<MallOrder> {
}
- 測試類
@RunWith(SpringRunner.class)
@SpringBootTest
public class OnedbApplicationTests {
@Resource
private MallOrderMapper orderMapper;
@Test
public void addOrder(){
for(int i = 0 ; i < 10 ; i ++){
MallOrder order = new MallOrder();
order.setOrderName("第"+i+"個訂單");
orderMapper.insert(order);
}
}
}
分庫分表-inline模式-普通不支援範圍查詢
- 首先要自己建表(真實表):
- 這裡就是在test資料庫裡建兩張相同的表mall_order_1 \ mall_order_2。在test2中建兩張相同的表mall_order_1 \ mall_order_2 。建表語句同上。
- 依賴同上:放在父工程pom裡即可
- 配置檔案:
# 應用名稱
spring.application.name=twodb
#配置資料庫别名:兩個資料庫
spring.shardingsphere.datasource.names=db1,db2
#第一個資料庫 庫名:test
spring.shardingsphere.datasource.db1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db1.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.shardingsphere.datasource.db1.username=root
spring.shardingsphere.datasource.db1.password=root
#第二個資料庫 庫名:test2
spring.shardingsphere.datasource.db2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db2.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.shardingsphere.datasource.db2.username=root
spring.shardingsphere.datasource.db2.password=root
#真實表有哪些
spring.shardingsphere.sharding.tables.mall_order.actual-data-nodes=db$->{1..2}.mall_order_$->{1..2}
#使用雪花算法自動生成id/主鍵生成政策
spring.shardingsphere.sharding.tables.mall_order.key-generator.column=id
spring.shardingsphere.sharding.tables.mall_order.key-generator.type=SNOWFLAKE
#spring.shardingsphere.sharding.tables.mall_order.key-generator.props.worker.id=1
#分片(分表:table-strategy)政策
#分片鍵ID
spring.shardingsphere.sharding.tables.mall_order.table-strategy.inline.sharding-column=id
#分片算法:根據ID是奇數->mall_order_1;是偶數->mall_order_2
spring.shardingsphere.sharding.tables.mall_order.table-strategy.inline.algorithm-expression=mall_order_$->{id%2+1}
#分片(分庫:database-strategy)政策
#分片鍵ID
spring.shardingsphere.sharding.tables.mall_order.database-strategy.inline.sharding-column=id
#分片算法:根據ID是奇數->db1 = test;是偶數->db2 = test2
spring.shardingsphere.sharding.tables.mall_order.database-strategy.inline.algorithm-expression=db$->{id%2+1}
#顯示sql語句
spring.shardingsphere.props.sql.show = true
spring.main.allow-bean-definition-overriding=true
- mapper同上
- 測試用例
@SpringBootTest
@RunWith(SpringRunner.class)
public class TwodbApplicationTests {
@Resource
private MallOrderMapper orderMapper;
/**
* 向兩個資料庫四張表插入資料
*/
@Test
public void addOrderToDB() {
for(int i = 0 ; i < 10 ; i ++){
MallOrder order = new MallOrder();
order.setOrderName("分庫後的第"+i+"個訂單");
orderMapper.insert(order);
}
}
/**
* 按id查找某條資料
* Logic SQL: SELECT id,order_name FROM mall_order WHERE (id = ?)
* Actual SQL: db2 ::: SELECT id,order_name FROM mall_order_2
* shardingsphere已經按政策優化查詢sql,僅在id可能存在的test2庫的mall_order_2這張表中進行一次查詢
*/
@Test
public void queryDataById(){
QueryWrapper<MallOrder> wrapper = new QueryWrapper<>();
wrapper.eq("id",1415550634731560961L);
MallOrder mallOrder = orderMapper.selectOne(wrapper);
System.out.println(mallOrder);
}
/**
* 範圍查詢:ID在xxx~zzz之間的所有資料查詢
* Inline strategy cannot support this type sharding:RangeRouteValue
* 使用inline模式是不支援範圍查詢的
*/
@Test
public void queryDataByRang(){
QueryWrapper<MallOrder> wrapper = new QueryWrapper<>();
wrapper.between("id",1415550634731560961L,1415550634748338178L);
List<MallOrder> mallOrders = orderMapper.selectList(wrapper);
mallOrders.forEach(mallOrder -> System.out.println(mallOrder));
}
/**
* 按id排序查詢出所有資料
* Logic SQL: SELECT id,order_name FROM mall_order
* Actual SQL: db1 ::: SELECT id,order_name FROM mall_order_1
* Actual SQL: db1 ::: SELECT id,order_name FROM mall_order_2
* Actual SQL: db2 ::: SELECT id,order_name FROM mall_order_1
* Actual SQL: db2 ::: SELECT id,order_name FROM mall_order_2
* 兩個庫的四張表全部查詢一遍(有待優化)
*/
@Test
public void queryDataBySort(){
QueryWrapper<MallOrder> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
List<MallOrder> mallOrders = orderMapper.selectList(wrapper);
mallOrders.forEach(mallOrder -> System.out.println(mallOrder));
}
}
注:inline模式不支援範圍查詢,使用standard自定義規則後實作範圍查詢
分庫分表-standard模式-範圍查詢
- 相同的sql和依賴和mapper省略
- 配置檔案
# 應用名稱
spring.application.name=twodb-standard
#配置資料庫别名:兩個資料庫
spring.shardingsphere.datasource.names=db1,db2
#第一個資料庫 庫名:test
spring.shardingsphere.datasource.db1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db1.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.shardingsphere.datasource.db1.username=root
spring.shardingsphere.datasource.db1.password=root
#第二個資料庫 庫名:test2
spring.shardingsphere.datasource.db2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db2.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.shardingsphere.datasource.db2.username=root
spring.shardingsphere.datasource.db2.password=root
#真實表有哪些
spring.shardingsphere.sharding.tables.mall_order.actual-data-nodes=db$->{1..2}.mall_order_$->{1..2}
#使用雪花算法自動生成id/主鍵生成政策
spring.shardingsphere.sharding.tables.mall_order.key-generator.column=id
spring.shardingsphere.sharding.tables.mall_order.key-generator.type=SNOWFLAKE
#spring.shardingsphere.sharding.tables.mall_order.key-generator.props.worker.id=1
#分片(分表:table-strategy)政策
#分片鍵ID
spring.shardingsphere.sharding.tables.mall_order.table-strategy.standard.sharding-column=id
#分表算法(需自己實作):
spring.shardingsphere.sharding.tables.mall_order.table-strategy.standard.precise-algorithm-class-name=com.lixiunan.twodbstandard.algorithm.MyTablePreciseAlgorithm
#表範圍查詢算法(需自己實作):
spring.shardingsphere.sharding.tables.mall_order.table-strategy.standard.range-algorithm-class-name=com.lixiunan.twodbstandard.algorithm.MyTableRangeAlgorithm
#分片(分庫:database-strategy)政策
#分片鍵ID
spring.shardingsphere.sharding.tables.mall_order.database-strategy.standard.sharding-column=id
#分庫算法(需自己實作):
spring.shardingsphere.sharding.tables.mall_order.database-strategy.standard.precise-algorithm-class-name=com.lixiunan.twodbstandard.algorithm.MyDBPreciseAlgorithm
#庫範圍查找算法(需自己實作):
spring.shardingsphere.sharding.tables.mall_order.database-strategy.standard.range-algorithm-class-name=com.lixiunan.twodbstandard.algorithm.MyDBRangeAlgorithm
#顯示sql語句
spring.shardingsphere.props.sql.show = true
spring.main.allow-bean-definition-overriding=true
- 自己寫實作類:自己實作分庫分表的規則,自己實作範圍查詢的方法等等
- 自己實作分庫政策
/**
* @Description : TODO 自己實作分庫政策
* @Author : lixiunan
* @Date : 2021/7/15
**/
public class MyDBPreciseAlgorithm implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
//把雪花算法生成的id取出
Long id = shardingValue.getValue();
//對id取摩得到的數字
BigInteger key =
BigInteger.valueOf(id).mod(new BigInteger("2")).add(new BigInteger("1"));
//生成真實表的表名
String dbName = "db" + key;
if(availableTargetNames.contains(dbName)){
return dbName;
}
throw new UnsupportedOperationException("找不到資料庫");
}
}
- 自己實作分表政策
/**
* @Description :
* TODO 自己定制insert時按照什麼算法去分發到不同表中:分片鍵的類型Lone傳入泛型,確定此算法在範圍查找時使用是有效的
* @Author : lixiunan
* @Date : 2021/7/15
**/
public class MyTablePreciseAlgorithm implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
//把雪花算法生成的id取出
Long id = shardingValue.getValue();
//對id取摩得到表名的數字
BigInteger key =
BigInteger.valueOf(id).mod(new BigInteger("2")).add(new BigInteger("1"));
//生成真實表的表名
String tableName = shardingValue.getLogicTableName() + "_" + key;
if(availableTargetNames.contains(tableName)){
return tableName;
}else {
throw new UnsupportedOperationException("找不到表名");
}
}
}
- 自己實作範圍查找(庫 + 表)
/**
* @Description : TODO 分為查找時分庫政策定制
* @Author : lixiunan
* @Date : 2021/7/15
**/
public class MyDBRangeAlgorithm implements RangeShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(
Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
//範圍查詢庫
return Arrays.asList("db1","db2");
}
}
/**
* @Description : TODO 定制範圍查找時分表查找政策
* @Author : lixiunan
* @Date : 2021/7/15
**/
public class MyTableRangeAlgorithm implements RangeShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(
Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
String logicTableName = shardingValue.getLogicTableName();
//範圍查詢表
return Arrays.asList(logicTableName+"_1",logicTableName+"_2");
}
}
- 測試用例
@SpringBootTest
@RunWith(SpringRunner.class)
public class TwodbStandardApplicationTests {
@Resource
private MallOrderMapper orderMapper;
/**
* 向兩個資料庫四張表插入資料
*/
@Test
public void addOrderToDB() {
for(int i = 0 ; i < 10 ; i ++){
MallOrder order = new MallOrder();
order.setOrderName("standard中第"+i+"個訂單");
orderMapper.insert(order);
}
}
/**
* 範圍查詢:
* Logic SQL: SELECT id,order_name FROM mall_order WHERE (id BETWEEN ? AND ?)
* Actual SQL: db1 ::: SELECT id,order_name FROM mall_order_1 WHERE (id BETWEEN ? AND ?) ::: [1415550634731560961, 1415550634748338178]
* Actual SQL: db1 ::: SELECT id,order_name FROM mall_order_2 WHERE (id BETWEEN ? AND ?) ::: [1415550634731560961, 1415550634748338178]
* Actual SQL: db2 ::: SELECT id,order_name FROM mall_order_1 WHERE (id BETWEEN ? AND ?) ::: [1415550634731560961, 1415550634748338178]
* Actual SQL: db2 ::: SELECT id,order_name FROM mall_order_2 WHERE (id BETWEEN ? AND ?) ::: [1415550634731560961, 1415550634748338178]
*
*
* 使用inline模式是不支援範圍查詢的,standard可以按照算法提供的方法或表名庫名進行範圍查找
*/
@Test
public void queryDataByRang(){
QueryWrapper<MallOrder> wrapper = new QueryWrapper<>();
wrapper.between("id",1415550634731560961L,1415550634748338178L);
List<MallOrder> mallOrders = orderMapper.selectList(wrapper);
mallOrders.forEach(mallOrder -> System.out.println(mallOrder));
}
}
分庫分表-complex模式-混合字段範圍查詢
- 相同的sql和依賴和mapper省略
- 配置檔案
# 應用名稱
spring.application.name=twodb-complex
#配置資料庫别名:兩個資料庫
spring.shardingsphere.datasource.names=db1,db2
#第一個資料庫 庫名:test
spring.shardingsphere.datasource.db1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db1.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.shardingsphere.datasource.db1.username=root
spring.shardingsphere.datasource.db1.password=root
#第二個資料庫 庫名:test2
spring.shardingsphere.datasource.db2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db2.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.shardingsphere.datasource.db2.username=root
spring.shardingsphere.datasource.db2.password=root
#真實表有哪些
spring.shardingsphere.sharding.tables.product.actual-data-nodes=db$->{1..2}.product_$->{1..2}
#分片(分表:table-strategy)政策
#分片鍵ID:可以多個ID聯合
spring.shardingsphere.sharding.tables.product.table-strategy.complex.sharding-columns=id,store_id
#分表算法(需自己實作):
spring.shardingsphere.sharding.tables.product.table-strategy.complex.algorithm-class-name=com.lixiunan.twodbcomplex.algorithm.MyComplexTableAlgorithm
#分片(分庫:database-strategy)政策
#分片鍵ID:#分片鍵ID:
spring.shardingsphere.sharding.tables.product.database-strategy.complex.sharding-columns=id,store_id
#分庫算法(需自己實作):
spring.shardingsphere.sharding.tables.product.database-strategy.complex.algorithm-class-name=com.lixiunan.twodbcomplex.algorithm.MyComplexDBAlgorithm
#顯示sql語句
spring.shardingsphere.props.sql.show = true
spring.main.allow-bean-definition-overriding=true
自己實作存儲&範圍查找(庫 + 表) 的政策
public class MyComplexDBAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> shardingValue) {
//擷取店鋪ID集合
Collection<Long> storeIdCollection =
shardingValue.getColumnNameAndShardingValuesMap().get("store_id");
//建立新集合
ArrayList<String> result = new ArrayList<String>();
//政策為取摩爾
for (Long storeId : storeIdCollection){
BigInteger storeIdInteger = BigInteger.valueOf(storeId);
BigInteger key =
(storeIdInteger.mod(new BigInteger("2"))).add(new BigInteger("1"));
result.add("db"+key);
}
return result;
}
}
public class MyComplexTableAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> shardingValue) {
//擷取店鋪ID集合
Collection<Long> storeIdCollection =
shardingValue.getColumnNameAndShardingValuesMap().get("store_id");
//擷取真實表字首名稱
String logicTableName = shardingValue.getLogicTableName();
//建立新集合
ArrayList<String> result = new ArrayList<String>();
//政策為取摩爾
for (Long storeId : storeIdCollection){
BigInteger storeIdInteger = BigInteger.valueOf(storeId);
BigInteger key =
(storeIdInteger.mod(new BigInteger("2"))).add(new BigInteger("1"));
result.add(logicTableName+"_"+key);
}
return result;
}
}
測試類——支援混合id範圍條件查詢
@RunWith(SpringRunner.class)
@SpringBootTest
public class TwodbComplexApplicationTests {
@Resource
private ProductMapper productMapper;
@Resource
private StoreMapper storeMapper;
/**
*添加資料
*/
@Test
public void add() {
for(int i = 0 ; i < 10 ; i ++){
Product product = new Product();
Long idLong = Long.valueOf(202110L + i);
product.setId(idLong);
Long storeIdLong = Long.valueOf(676 + i);
product.setStoreId(storeIdLong);
product.setProductName("complex第"+i+"個商品");
product.setProductStatus(((i % 2)+1)+"");
productMapper.insert(product);
}
}
/**
* 缺少參數不能查詢
*/
@Test
public void queryRange(){
QueryWrapper<Product> wrapper = new QueryWrapper<>();
wrapper.between("store_id",670L,680L);
List<Product> products = productMapper.selectList(wrapper);
products.forEach(product -> System.out.println(product));
}
/**
* 支援(必須)混合ID複雜查詢,如配置中的
*/
@Test
public void queryCourseComplex(){
QueryWrapper<Product> wrapper = new QueryWrapper<>();
wrapper.between("id",202100L,202114L);
wrapper.eq("store_id",677L);
List<Product> products = productMapper.selectList(wrapper);
products.forEach(product -> System.out.println(product));
}
}
分庫分表-hint模式-指定資料庫/表
- 相同的sql和依賴和mapper省略
- 配置檔案
# 應用名稱
spring.application.name=twodb-hint
#配置資料庫别名:兩個資料庫
spring.shardingsphere.datasource.names=db1,db2
#第一個資料庫 庫名:test
spring.shardingsphere.datasource.db1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db1.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.shardingsphere.datasource.db1.username=root
spring.shardingsphere.datasource.db1.password=root
#第二個資料庫 庫名:test2
spring.shardingsphere.datasource.db2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db2.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.shardingsphere.datasource.db2.username=root
spring.shardingsphere.datasource.db2.password=root
#真實表有哪些
spring.shardingsphere.sharding.tables.product.actual-data-nodes=db$->{1..2}.product_$->{1..2}
#使用雪花算法自動生成id/主鍵生成政策
spring.shardingsphere.sharding.tables.product.key-generator.column=id
spring.shardingsphere.sharding.tables.product.key-generator.type=SNOWFLAKE
#分片(分表:table-strategy)政策
#分片鍵ID:可以多個ID聯合
#分表算法(需自己實作hint模式):
spring.shardingsphere.sharding.tables.product.table-strategy.hint.algorithm-class-name=com.lixiunan.twodbhint.algorithm.MyHintTableAlgorithm
#分片(分庫:database-strategy)政策
#分片鍵ID:#分片鍵ID:
#分庫算法:不指定
#顯示sql語句
spring.shardingsphere.props.sql.show = true
spring.main.allow-bean-definition-overriding=true
自己實作如何制定表/庫
/**
* @Description : TODO hint可向指定表/庫中添加/擷取資料
* @Author : lixiunan
* @Date : 2021/7/19
**/
public class MyHintTableAlgorithm implements HintShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Long> shardingValue) {
String key =
shardingValue.getLogicTableName() + "_" + shardingValue.getValues().toArray()[0];
if(availableTargetNames.contains(key)){
return Arrays.asList(key);
}
throw new UnsupportedOperationException("找不到表");
}
}
測試
@RunWith(SpringRunner.class)
@SpringBootTest
public class TwodbHintApplicationTests {
@Resource
private ProductMapper productMapper;
/**
* 指定查詢的表
* SELECT id,store_id,product_name,product_status FROM product
* Actual SQL: db1 ::: SELECT id,store_id,product_name,product_status FROM product_1
* Actual SQL: db2 ::: SELECT id,store_id,product_name,product_status FROM product_1
*/
@Test
public void queryByHint1(){
HintManager hintManager = HintManager.getInstance();
hintManager.addTableShardingValue("product",1);
List<Product> products = productMapper.selectList(null);
products.forEach(product -> System.out.println(product));
hintManager.close();
}
/**
* Logic SQL: SELECT id,store_id,product_name,product_status FROM product
* Actual SQL: db1 ::: SELECT id,store_id,product_name,product_status FROM product_2
* Actual SQL: db2 ::: SELECT id,store_id,product_name,product_status FROM product_2
*/
@Test
public void queryByHint2(){
HintManager hintManager = HintManager.getInstance();
hintManager.addTableShardingValue("product",2);
List<Product> products = productMapper.selectList(null);
products.forEach(product -> System.out.println(product));
hintManager.close();
}
}