(三)、Sharding-JDBC強制路由


在一些應用場景中,分片條件並不存在於SQL,而存在於外部業務邏輯。因此需要提供一種通過在外部業務代碼中指定路由配置的一種方式,在ShardingSphere中叫做Hint。如果使用Hint指定了強制分片路由,那么SQL將會無視原有的分片邏輯,直接路由至指定的數據節點操作。
HintManager主要使用ThreadLocal管理分片鍵信息,進行hint強制路由。在代碼中向HintManager添加的配置信息只能在當前線程內有效。

Hint使用場景:
  • 數據分片操作,如果分片鍵沒有在SQL或數據表中,而是在業務邏輯代碼中
  • 讀寫分離操作,如果強制在主庫進行某些數據操作
Hint使用過程:
  • 編寫分庫或分表路由策略,實現HintShardingAlgorithm接口

package com.qjc.hint;

import org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.hint.HintShardingValue;

import java.util.ArrayList;
import java.util.Collection;

/**
 * @ClassName: MyHintShardingAlgorithm
 * @Description: Hint使用場景:
 * 1、數據分片操作,如果分片鍵沒有在SQL或數據表中,而是在業務邏輯代碼中
 * 2、讀寫分離操作,如果強制在主庫進行某些數據操作
 * @Author: qjc
 * @Date: 2021/11/10 6:17 下午
 */
public class MyHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Long> shardingValue) {
        Collection<String> result = new ArrayList<>();
        for (String each : availableTargetNames) {
            for (Long value : shardingValue.getValues()) {
                if (each.endsWith(String.valueOf(value % 2))) {
                    result.add(each);
                }
            }
        }
        return result;
    }
}
  • 在配置文件指定分庫或分表策略

# 命名數據源  這個是自定義的
spring.shardingsphere.datasource.names=ds-0,ds-1
# 配置數據源ds-0
spring.shardingsphere.datasource.ds-0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds-0.driverClassName=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-0.url=jdbc:mysql://127.0.0.1:3306/ds-0?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds-0.username=root
spring.shardingsphere.datasource.ds-0.password=123456
# 配置數據源ds-1
spring.shardingsphere.datasource.ds-1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds-1.driverClassName=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-1.url=jdbc:mysql://127.0.0.1:3306/ds-1?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds-1.username=root
spring.shardingsphere.datasource.ds-1.password=123456
# 配置默認數據源ds-0
spring.shardingsphere.sharding.default-data-source-name=ds-0

# Hint強制路由
# 使用t_city表測試強制路由到庫
spring.shardingsphere.sharding.tables.t_city.database-strategy.hint.algorithm-class-name=com.qjc.hint.MyHintShardingAlgorithm

# 使用t_order表測試強制路由到庫和表
spring.shardingsphere.sharding.tables.t_order.database-strategy.hint.algorithm-class-name=com.qjc.hint.MyHintShardingAlgorithm
spring.shardingsphere.sharding.tables.t_order.table-strategy.hint.algorithm-class-name=com.qjc.hint.MyHintShardingAlgorithm
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds-$->{0..1}.t_order_$->{0..1}
  • 在代碼執行查詢前使用HintManager指定執行策略值

package com.qjc;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qjc.entity.TCity;
import com.qjc.entity.TOrder;
import com.qjc.mapper.TCityMapper;
import com.qjc.mapper.TOrderMapper;
import org.apache.shardingsphere.api.hint.HintManager;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ShardingSphereDemoApplication.class)
public class TestHintAlgorithm {

    @Resource
    private TCityMapper cityMapper;
    @Autowired
    private TOrderMapper orderMapper;

    @Test
    public void testAdd() {
        HintManager hintManager = HintManager.getInstance();
        // 插入10條數據,通過MyHintShardingAlgorithm可知,強制路由到ds-${value%2}
        hintManager.setDatabaseShardingValue(1L);
        for (int i = 0; i < 10; i++) {
            TCity city = new TCity();
            city.setName("商丘市" + i);
            city.setProvince("河南省" + i);
            cityMapper.insert(city);
        }
    }

    @Test
    public void test1() {
        HintManager hintManager = HintManager.getInstance();
        // 通過MyHintShardingAlgorithm可知,強制路由到ds-${value%2}
//        hintManager.setDatabaseShardingValue(1L);
        hintManager.addDatabaseShardingValue("t_city", 1L);
        List<TCity> list = cityMapper.selectList(new QueryWrapper<>());
        list.forEach(city -> {
            System.out.println(city.getId() + " " + city.getName() + " " + city.getProvince());
        });
    }

    @Test
    public void test2() {
        HintManager hintManager = HintManager.getInstance();
        // 強制路由到庫ds-1
        hintManager.addDatabaseShardingValue("t_order", 1L);
        // 強制路由到表t_order_1
        hintManager.addTableShardingValue("t_order", 1L);
        List<TOrder> list = orderMapper.selectList(new QueryWrapper<>());
        list.forEach(order -> {
            System.out.println(order.getOrderId() + " " + order.getOrderNo());
        });
    }

}
在讀寫分離結構中,為了避免主從同步數據延遲及時獲取剛添加或更新的數據,可以采用強制路由走主庫查詢實時數據,使用hintManager.setMasterRouteOnly設置主庫路由即可。

測試插入數據,結果如下:

 也可以查看數據庫

 測試查詢

 這里演示的只是分庫,分庫分表的測試可以自行進行

分庫分表參考

SpringBoot2.0.3.RELEASE+sharding-jdbc4.1.0+mybatis-plus3.4.1+druid1.1.22 快速搭建分庫分表 - 劈天造陸 - 博客園 (cnblogs.com) 

完整代碼及sql腳本在:

https://gitee.com/xiaorenwu_dashije/sharding-sphere-demo.git


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM