一、什么是强制路由?
强制路由与一般的分库分表路由不同,它并没有使用任何的分片键和分片策略。有时候,我们需要为 SQL 执行开一个“后门”,允许在没有分片键的情况下,同样可以在外部设置目标数据库和表,这就是强制路由的设计理念
二、ShardingSphere 强制路由设计
基于 Hint 进行强制路由的设计和开发过程需要遵循一定的约定,同时,ShardingSphere 也提供了专门的 HintManager 来简化强制路由的开发过程
HintManager 类的使用方式比较固化,我们可以通过查看源码中的类定义以及核心变量来理解它所包含的操作内容:
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 使用了 ThreadLocal 来保存 HintManager 实例。显然,基于这种处理方式,所有分片信息的作用范围就是当前线程。我们也看到了用于分别存储数据库分片值和数据表分片值的两个 Multimap 对象,以及分别用于指定是否只有数据库分片,以及是否只路由主库的标志位。可以想象,HintManager 基于这些变量开放了一组 get/set 方法供开发人员根据具体业务场景进行分片键的设置
同时,在类的定义上,我们也注意到 HintManager 实现了 AutoCloseable 接口,这个接口是在 JDK7 中引入的一个新接口,用于自动释放资源。AutoCloseable 接口只有一个 close 方法,我们可以实现这个方法来释放自定义的各种资源
public interface AutoCloseable {
void close() throws Exception;
}
在 JDK1.7 之前,我们需要手动通过 try/catch/finally 中的 finally 语句来释放资源,而使用 AutoCloseable 接口,在 try 语句结束的时候,不需要实现 finally 语句就会自动将这些资源关闭,JDK 会通过回调的方式,调用 close 方法来做到这一点。这种机制被称为 try with resource。AutoCloseable 还提供了语法糖,在 try 语句中可以同时使用多个实现这个接口的资源,并通过使用分号进行分隔
在 JDK1.7 之前,我们需要手动通过 try/catch/finally 中的 finally 语句来释放资源,而使用 AutoCloseable 接口,在 try 语句结束的时候,不需要实现 finally 语句就会自动将这些资源关闭,JDK 会通过回调的方式,调用 close 方法来做到这一点。这种机制被称为 try with resource。AutoCloseable 还提供了语法糖,在 try 语句中可以同时使用多个实现这个接口的资源,并通过使用分号进行分隔
HintManager 中通过实现 AutoCloseable 接口支持资源的自动释放,事实上,JDBC 中的 Connection 和 Statement 接口的实现类同样也实现了这个 AutoCloseable 接口
对于 HintManager 而言,所谓的资源实际上就是 ThreadLocal 中所保存的 HintManager 实例。下面这段代码实现了 AutoCloseable 接口的 close 方法,进行资源的释放:
public static void clear() {
HINT_MANAGER_HOLDER.remove()