Hint #
数据分片 强制路由 #
背景信息 #
SphereEx-DBPlusEngine 使用 ThreadLocal 管理分片键值进行强制路由。 可以通过编程的方式向 HintManager 中添加分片值,该分片值仅在当前线程内生效。 SphereEx-DBPlusEngine 还可以通过 SQL 中增加注释的方式进行强制路由。
Hint 的主要使用场景:
- 分片字段不存在 SQL 和数据库表结构中,而存在于外部业务逻辑。
- 强制在指定数据库进行某些数据操作。
操作步骤 #
- 调用 HintManager.getInstance() 获取 HintManager 实例;
- 调用 HintManager.addDatabaseShardingValue,HintManager.addTableShardingValue 方法设置分片键值;
- 执行 SQL 语句完成路由和执行;
- 调用 HintManager.close 清理 ThreadLocal 中的内容。
使用 Hint 分片 配置示例 #
规则配置 #
Hint 分片算法需要用户实现 org.apache.shardingsphere.sharding.api.sharding.hint.HintShardingAlgorithm
接口。
Apache ShardingSphere 在进行路由时,将会从 HintManager 中获取分片值进行路由操作。
参考配置如下:
copyrules:
- !SHARDING
tables:
t_order:
actualDataNodes: demo_ds_${0..1}.t_order_${0..1}
databaseStrategy:
hint:
algorithmClassName: xxx.xxx.xxx.HintXXXAlgorithm
tableStrategy:
hint:
algorithmClassName: xxx.xxx.xxx.HintXXXAlgorithm
defaultTableStrategy:
none:
defaultKeyGenerateStrategy:
type: SNOWFLAKE
column: order_id
props:
sql-show: true
获取 HintManager #
copyHintManager hintManager = HintManager.getInstance();
添加分片键值 #
- 使用
hintManager.addDatabaseShardingValue
来添加数据源分片键值。 - 使用
hintManager.addTableShardingValue
来添加表分片键值。
分库不分表情况下,强制路由至某一个分库时,可使用
hintManager.setDatabaseShardingValue
方式设置分片值。
清除分片键值 #
分片键值保存在 ThreadLocal 中,所以需要在操作结束时调用 hintManager.close()
来清除 ThreadLocal 中的内容。
hintManager 实现了 AutoCloseable 接口,可推荐使用 try with resource 自动关闭。
完整代码示例 #
copy// Sharding database and table with using 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()) {
// ...
}
}
}
// Sharding database without sharding table and routing to only one database with using 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()) {
// ...
}
}
}
使用 SQL 注释的方式 配置示例 #
使用规范 #
SQL Hint 功能的注释格式暂时只支持 /* */
,内容需要以 SHARDINGSPHERE_HINT:
开始,可选的属性包括:
{table}.SHARDING_DATABASE_VALUE
:用于添加{table}
表对应的数据源分片键值,多个属性使用逗号分隔;{table}.SHARDING_TABLE_VALUE
:用于添加{table}
表对应的表分片键值,多个属性使用逗号分隔。
分库不分表情况下,强制路由至某一个分库时,可使用
SHARDING_DATABASE_VALUE
方式设置分片,无需指定{table}
。
完整示例 #
copy/* SHARDINGSPHERE_HINT: t_order.SHARDING_DATABASE_VALUE=1, t_order.SHARDING_TABLE_VALUE=1 */
SELECT * FROM t_order;
读写分离 强制路由 #
背景信息 #
SphereEx-DBPlusEngine 使用 ThreadLocal 管理主库路由标记进行强制路由。 可以通过编程的方式向 HintManager 中添加主库路由标记,该值仅在当前线程内生效。 SphereEx-DBPlusEngine 还可以通过 SQL 中增加注释的方式进行主库路由。
Hint 在读写分离场景下,主要用于强制在主库进行某些数据操作。
操作步骤 #
- 调用
HintManager.getInstance()
获取 HintManager 实例; - 调用
HintManager.setWriteRouteOnly()
方法设置主库路由标记; - 执行 SQL 语句完成路由和执行;
- 调用
HintManager.close()
清理 ThreadLocal 中的内容。
使用 Hint 强制主库路由 配置示例 #
获取 HintManager #
与基于 Hint 的数据分片相同。
设置主库路由 #
使用 hintManager.setWriteRouteOnly 设置主库路由。
清除分片键值 #
与基于 Hint 的数据分片相同。
完整代码示例 #
copyString sql = "SELECT * FROM t_order";
try (HintManager hintManager = HintManager.getInstance();
Connection conn = dataSource.getConnection();
PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
hintManager.setWriteRouteOnly();
try (ResultSet rs = preparedStatement.executeQuery()) {
while (rs.next()) {
// ... }
}
}
使用 SQL 注释的方式强制主库路由配置示例 #
使用规范 #
SQL Hint 功能的注释格式暂时只支持 /* */
,内容需要以 SHARDINGSPHERE_HINT:
开始,属性名为 WRITE_ROUTE_ONLY
。
完整示例 #
copy/* SHARDINGSPHERE_HINT: WRITE_ROUTE_ONLY=true */
SELECT * FROM t_order;
使用 Hint 强制路由指定数据库配置示例 #
获取 HintManager #
与基于 Hint 的数据分片相同。
设置路由至指定数据库 #
- 使用
hintManager.setDataSourceName
设置数据库名称。
完整代码示例 #
copyString sql = "SELECT * FROM t_order";
try (HintManager hintManager = HintManager.getInstance();
Connection conn = dataSource.getConnection();
PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
hintManager.setDataSourceName("ds_0");
try (ResultSet rs = preparedStatement.executeQuery()) {
while (rs.next()) {
// ...
}
}
}
使用 SQL 注释的方式强制路由指定数据库配置示例 #
使用规范 #
SQL Hint 功能目前只支持路由至一个数据源。 注释格式暂时只支持 /* */
,内容需要以 SHARDINGSPHERE_HINT:
开始,属性名为 DATA_SOURCE_NAME
。
如果使用 MySQL
客户端连接需要添加 -c
选项保留注释,客户端默认是 --skip-comments
过滤注释。
完整示例 #
copy/* SHARDINGSPHERE_HINT: DATA_SOURCE_NAME=ds_0 */
SELECT * FROM t_order;