Spring Boot整合Sharding-JDBC实现强制路由

目录

强制路由

ShardingSphere使用ThreadLocal管理分片键值进行Hint强制路由。可以通过编程的方式向HintManager中添加分片值,该分片值仅在当前线程内生效。 Hint方式主要使用场景:

  1. 分片字段不存在SQL中、数据库表结构中,而存在于外部业务逻辑。

  2. 强制在主库进行某些数据操作。

简单来说,强制路由可以让我们显式指定某个库或某个表来执行我们的数据库操作

HintManager

在Sharding-JDBC中,强制路由是依靠HintManager实现的, HintManager 是一种上下文,可以用于存储一些特殊的路由信息,以便在路由规则无法满足需求时进行强制路由和强制分库分表

java 复制代码
public final class HintManager implements AutoCloseable {
    //基于ThreadLocal存储HintManager实例
    private static final ThreadLocal<HintManager> HINT_MANAGER_HOLDER = new ThreadLocal<>();
    //数据库分片值
    private final Multimap<String, Comparable<?>> databaseShardingValues = HashMultimap.create();
    //数据表分片值
    private final Multimap<String, Comparable<?>> tableShardingValues = HashMultimap.create();
    //是否只有数据库分片
    private boolean databaseShardingOnly;
    //是否只路由主库
    private boolean masterRouteOnly;
    ...
}

获取HintManager

java 复制代码
HintManager hintManager = HintManager.getInstance();

强制分片

要使用HintManager进行强制路由分片,那么需要使用Hint分片算法,Hint分片算法需要我们实现org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm接口。ShardingSphere在进行Routing时,如果发现LogicTable的TableRule采用了 Hint的分片算法,将会从HintManager中获取分片值进行路由操作。

java 复制代码
/**
 * 自定义强制路由类
 */
public class MyHintShardingAlgorithm implements HintShardingAlgorithm<Long>  {


    /**
     *  定义强制路由策略
     *  collection: 分片目标:表示当前可用的数据源或数据表名称,对哪些数据库 表进行分片,比如做分库路由
     *  hintShardingValue: 分片值, 分片键的值
     */
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Long> shardingValue) {
        Collection<String> result = new ArrayList<>();
        // 遍历数据源
        for (String actualDb : availableTargetNames) {
            // hintShardingValue: 代表分片值, 指的是使用者对分片键赋的值
            Collection<Long> values = shardingValue.getValues();
            for (Long value : values) {
                //直接路由到与我们传入的路由值相等的数据源上
                if(actualDb.endsWith(String.valueOf(value))){
                    result.add(actualDb);
                }
            }
        }
        return result;
    }
}

配置

java 复制代码
# 对t_course表进行强制路由
# 强制路由库设置
spring.shardingsphere.sharding.tables.t_course.database-strategy.hint.algorithm-class-name=com.example.demo.shardingsphere.MyHintShardingAlgorithm
# 强制路由表设置
spring.shardingsphere.sharding.tables.t_course.table-strategy.hint.algorithm-class-name=com.example.demo.shardingsphere.MyHintShardingAlgorithm

添加分片键值

使用hintManager.addDatabaseShardingValue来添加数据源分片键值。

使用hintManager.addTableShardingValue来添加表分片键值。

分库不分表情况下,强制路由至某一个分库时,可使用hintManager.setDatabaseShardingValue方式添加分片。

清除分片键值

分片键值保存在ThreadLocal中,所以需要在操作结束时调用hintManager.close()来清除ThreadLocal中的内容。

close方法实际调用的是clear方法,而clear方法调用的是ThreadLocal的remove方法

java 复制代码
 	/**
     * Clear threadlocal for hint manager.
     */
    public static void clear() {
        HINT_MANAGER_HOLDER.remove();
    }
    
    @Override
    public void close() {
        HintManager.clear();
    }

下面是一个简单的示例

java 复制代码
		 //使用hintManager对数据库和表进行分片
  		String sql = "SELECT * FROM t_order";
        try (HintManager hintManager = HintManager.getInstance();
             Connection conn = dataSource.getConnection();
             PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
            hintManager.addDatabaseShardingValue("t_order", 1);
            hintManager.addTableShardingValue("t_order", 2);
            try (ResultSet rs = preparedStatement.executeQuery()) {
                while (rs.next()) {
                    // ...
                }
            }
        }

		//使用hintmanager对数据库进行分片,不使用分片表,只路由到一个数据库
        String sql = "SELECT * FROM t_order";
        try (HintManager hintManager = HintManager.getInstance();
             Connection conn = dataSource.getConnection();
             PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
            hintManager.setDatabaseShardingValue(3);
            try (ResultSet rs = preparedStatement.executeQuery()) {
                while (rs.next()) {
                    // ...
                }
            }
        }

可以看到,单独路由某个库,使用setDatabaseShardingValue设置值即可,如果需要路由库和表,则需要设置addDatabaseShardingValue和addTableShardingValue两个值

强制访问主库

在读写分离的情况,有些时候,我们想要直接访问主库,来保证数据的实时性,这就可以使用我们的强制主库路由

设置主库路由

使用hintManager.setMasterRouteOnly方法设置主库路由,通过调用该方法,可以指定只路由到主库

示例

java 复制代码
String sql = "SELECT * FROM t_order";
try (
        HintManager hintManager = HintManager.getInstance();
        Connection conn = dataSource.getConnection();
        PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
    hintManager.setMasterRouteOnly();
    try (ResultSet rs = preparedStatement.executeQuery()) {
        while (rs.next()) {
            // ...
        }
    }
}

只需要调用 hintManager.setMasterRouteOnly()方法即可,setMasterRouteOnly()会将只进行主库路由的标识设置为 true,这样在后续的数据路由过程中,将忽略从库的存在,只路由到主库。

java 复制代码
public void setMasterRouteOnly() {
        masterRouteOnly = true;
}

使用之后,调用close或clear方法清除ThreadLocal变量

相关推荐
qfljg14 分钟前
OpenRewrite 实战指南
java
Sylvia33.18 分钟前
LOL实时数据接入深度解析:从WebSocket到完整数据模型
java·网络·python·websocket·网络协议
jyOverQ19 分钟前
RabbitMQ 消息积压怎么办?Prefetch、消费者并发与扩容
分布式·后端·rabbitmq
知行合一。。。5 小时前
RAG--03--Milvus基本用法
数据库·oracle·milvus
2601_962071576 小时前
【Java报错已解决】org.springframework.beans.factory.BeanCreationException
java·开发语言
TDengine (老段)6 小时前
TDengine 线程模型 — 网络、调度、执行
大数据·数据库·物联网·制造·时序数据库·tdengine·涛思数据
zww89491116 小时前
酒馆预约系统开发实战:从需求分析到上线全流程指南
java·eclipse
上学的小垃圾7 小时前
01-数据库系统概述
数据库
二进制漫游记7 小时前
FastAPI项目集成 Qdrant向量数据库+阿里云Embedding完整实战(工具封装+业务调用)
数据库·python·阿里云·embedding
2501_928996227 小时前
GPT-4o换DeepSeek迁移成本多少?中科热备解析API聚合平台技术账本
前端·数据库·人工智能