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

相关推荐
小刘|2 分钟前
《Java 实现希尔排序:原理剖析与代码详解》
java·算法·排序算法
逊嘘21 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
morris13128 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
十叶知秋41 分钟前
【jmeter】jmeter的线程组功能的详细介绍
数据库·jmeter·性能测试
monkey_meng1 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马1 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng1 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员1 小时前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU1 小时前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea