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变量

相关推荐
儿时可乖了几秒前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol2 分钟前
java基础概念37:正则表达式2-爬虫
java
懒是一种态度2 分钟前
Golang 调用 mongodb 的函数
数据库·mongodb·golang
天海华兮4 分钟前
mysql 去重 补全 取出重复 变量 函数 和存储过程
数据库·mysql
xmh-sxh-131418 分钟前
jdk各个版本介绍
java
XINGTECODE32 分钟前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
天天扭码37 分钟前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶38 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺42 分钟前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序1 小时前
vue3 封装request请求
java·前端·typescript·vue