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

相关推荐
跟着珅聪学java26 分钟前
spring boot +Elment UI 上传文件教程
java·spring boot·后端·ui·elementui·vue
我命由我1234531 分钟前
Spring Boot 自定义日志打印(日志级别、logback-spring.xml 文件、自定义日志打印解读)
java·开发语言·jvm·spring boot·spring·java-ee·logback
lilye6632 分钟前
程序化广告行业(55/89):DMP与DSP对接及数据统计原理剖析
java·服务器·前端
徐小黑ACG1 小时前
GO语言 使用protobuf
开发语言·后端·golang·protobuf
·薯条大王4 小时前
MySQL联合查询
数据库·mysql
战族狼魂4 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
xyliiiiiL5 小时前
ZGC初步了解
java·jvm·算法
杉之5 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
morris1316 小时前
【redis】redis实现分布式锁
数据库·redis·缓存·分布式锁
hycccccch6 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq