天天看點

ShardingSphereJDBC分庫分表Demo【附源碼】資料庫相關知識脈絡圖ShardingSphere簡介ShardingSphere JDBC基本概念解釋ShardingSphere JDBC使用

資料庫相關知識脈絡圖

目錄

資料庫相關知識脈絡圖

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基本概念解釋

ShardingSphereJDBC分庫分表Demo【附源碼】資料庫相關知識脈絡圖ShardingSphere簡介ShardingSphere JDBC基本概念解釋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介紹:

  1. maven聚合項目:common包中實體類,其他包為不同配置的分庫分表demo依賴common。
  2. 使用mybatis plus 進行操作資料庫(測試用例簡單)。mapper在各個demo包中。
  3. 測試例子在各個demo的test包中。
  4. 配置檔案采用.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();
    }

}