Skip to content

Commit 010c917

Browse files
committed
update doc and add example of hint sharding value
1 parent 4d5ad8e commit 010c917

File tree

8 files changed

+122
-14
lines changed

8 files changed

+122
-14
lines changed

sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/api/HintShardingValueManager.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public final class HintShardingValueManager {
4747
*/
4848
public static void init() {
4949
if (null != SHARING_VALUE_CONTAINER.get()) {
50-
throw new ShardingJdbcException("CAN NOT register sharding value repeatedly");
50+
throw new ShardingJdbcException("CAN NOT init repeatedly");
5151
}
5252
SHARING_VALUE_CONTAINER.set(new ShardingValueContainer());
5353
}

sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/router/single/SingleTableRouter.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ private Collection<String> routeDataSources() {
8282
Optional<List<ShardingValue<?>>> hintDatabaseShardingValues = HintShardingValueManager.getShardingValueOfDatabase(logicTable);
8383
List<ShardingValue<?>> databaseShardingValues;
8484
if (hintDatabaseShardingValues.isPresent()) {
85-
databaseShardingValues = hintDatabaseShardingValues.get();
85+
databaseShardingValues = filterShardingValue(strategy.getShardingColumns(), hintDatabaseShardingValues.get());
8686
} else {
8787
databaseShardingValues = getShardingValues(strategy.getShardingColumns());
8888
}
@@ -98,7 +98,7 @@ private Collection<String> routeTables(final Collection<String> routedDataSource
9898
Optional<List<ShardingValue<?>>> hintTableShardingValues = HintShardingValueManager.getShardingValueOfTable(logicTable);
9999
List<ShardingValue<?>> tableShardingValues;
100100
if (hintTableShardingValues.isPresent()) {
101-
tableShardingValues = hintTableShardingValues.get();
101+
tableShardingValues = filterShardingValue(strategy.getShardingColumns(), hintTableShardingValues.get());
102102
} else {
103103
tableShardingValues = getShardingValues(strategy.getShardingColumns());
104104
}
@@ -120,6 +120,16 @@ private List<ShardingValue<?>> getShardingValues(final Collection<String> shardi
120120
return result;
121121
}
122122

123+
private List<ShardingValue<?>> filterShardingValue(final Collection<String> shardingColumns, final List<ShardingValue<?>> shardingValues) {
124+
List<ShardingValue<?>> result = new ArrayList<>(shardingColumns.size());
125+
for (ShardingValue<?> each : shardingValues) {
126+
if (shardingColumns.contains(each.getColumnName())) {
127+
result.add(each);
128+
}
129+
}
130+
return result;
131+
}
132+
123133
private void logBeforeRoute(final String type, final String logicTable, final Collection<?> targets, final Collection<String> shardingColumns, final List<ShardingValue<?>> shardingValues) {
124134
log.trace("Before {} sharding {} routes db names: {} sharding columns: {} sharding values: {}", type, logicTable, targets, shardingColumns, shardingValues);
125135
}

sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/AbstractDBUnitTest.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717

1818
package com.dangdang.ddframe.rdb.integrate;
1919

20-
import static org.dbunit.Assertion.assertEquals;
21-
2220
import java.io.File;
2321
import java.io.InputStream;
2422
import java.io.InputStreamReader;
@@ -28,9 +26,9 @@
2826
import java.util.HashMap;
2927
import java.util.List;
3028
import java.util.Map;
31-
3229
import javax.sql.DataSource;
3330

31+
import com.dangdang.ddframe.rdb.sharding.api.DatabaseType;
3432
import org.apache.commons.dbcp.BasicDataSource;
3533
import org.dbunit.DatabaseUnitException;
3634
import org.dbunit.IDatabaseTester;
@@ -44,11 +42,11 @@
4442
import org.h2.tools.RunScript;
4543
import org.junit.Before;
4644

47-
import com.dangdang.ddframe.rdb.sharding.api.DatabaseType;
45+
import static org.dbunit.Assertion.assertEquals;
4846

4947
public abstract class AbstractDBUnitTest {
5048

51-
public static final DatabaseType CURRENT_DB_TYPE = DatabaseType.H2;
49+
public static final DatabaseType CURRENT_DB_TYPE = DatabaseType.MySQL;
5250

5351
private static final Map<String, DataSource> DATA_SOURCES = new HashMap<>();
5452

sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/router/AbstractDynamicRouteSqlTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ protected void assertMultipleTargets(final List<ShardingValuePair> shardingValue
4545
final Collection<String> targetDataSources, final Collection<String> targetSQLs) throws SQLParserException {
4646
HintShardingValueManager.init();
4747
for (ShardingValuePair each : shardingValuePairs) {
48-
HintShardingValueManager.registerShardingValueOfDatabase(each.logicTable, "dynamic_virtual_order_id", each.binaryOperator, each.shardingValue);
49-
HintShardingValueManager.registerShardingValueOfTable(each.logicTable, "dynamic_virtual_order_id", each.binaryOperator, each.shardingValue);
48+
HintShardingValueManager.registerShardingValueOfDatabase(each.logicTable, "order_id", each.binaryOperator, each.shardingValue);
49+
HintShardingValueManager.registerShardingValueOfTable(each.logicTable, "order_id", each.binaryOperator, each.shardingValue);
5050
}
5151

5252
assertMultipleTargets(originSql, parameters, expectedSize, targetDataSources, targetSQLs);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
+++
2+
date = "2016-02-05T17:03:18+08:00"
3+
title = "基于暗示的分片键值注册方法"
4+
weight = 12
5+
+++
6+
7+
# 基于暗示的分片键值注册方法
8+
9+
> 提示:阅读本文前请详细预读 [使用指南](../user_guide)
10+
11+
## 背景
12+
`Shanrding-JDBC`有初步了解的朋友已经发现了:在编写分片算法的时候,传入的分片键值是来自`SQL`语句中`WHERE`条件的。
13+
例如逻辑表`t_order`如果其数据源分片键为`user_id`
14+
分片算法是奇数值路由到`db1`偶数值路由到`db2`;表分片键为`order_id`
15+
分片算法是奇数值路由到`t_order_1`偶数值路由到`t_order_2`,如果执行如下sql语句:
16+
```sql
17+
select * from t_order where user_id = 1 and order_id = 2
18+
```
19+
那么在数据源分片算法的`shardingValue`参数将会传入`1`用于分片计算,结果为路由到`db1`;
20+
表分片算法的`shardingValue`参数将会传入`2`用于分片计算,结果为路由到`t_order_2`。最终SQL为:
21+
```sql
22+
select * from db1.t_order_2 where user_id = 1 and order_id = 2
23+
```
24+
25+
__现有一个假设,如果`WHERE`中没有`user_id``order_id`的条件,那么是否可以进行分片计算呢?__
26+
27+
答案是肯定的。下面就介绍一下`Sharding-JDBC`对这个问题的解决方法。
28+
29+
## 基于暗示的分片键值管理器
30+
要解决上面的问题,我们使用`com.dangdang.ddframe.rdb.sharding.api.HintShardingValueManager`
31+
该管理器是使用`ThreadLocal`技术管理分片键值的。
32+
使用例子:
33+
```java
34+
String sql = "SELECT * FROM t_order";
35+
36+
try (
37+
Connection conn = dataSource.getConnection();
38+
PreparedStatement pstmt = conn.prepareStatement(sql)) {
39+
HintShardingValueManager.init();
40+
HintShardingValueManager.registerShardingValueOfDatabase("t_order", "user_id", 1);
41+
HintShardingValueManager.registerShardingValueOfTable("t_order", "order_id", 2);
42+
try (ResultSet rs = pstmt.executeQuery()) {
43+
while (rs.next()) {
44+
...
45+
}
46+
}
47+
} finally {
48+
HintShardingValueManager.clear();
49+
}
50+
```
51+
52+
### 初始化方法
53+
使用`HintShardingValueManager.init()`表示开始执行操作,此时会初始化`ThreadLocal`中的数据。
54+
55+
注意:__在一个线程中只能初始化一次__。否则会抛出`CAN NOT init repeatedly`的异常。
56+
57+
### 注册分片键值
58+
- 使用`HintShardingValueManager.registerShardingValueOfDatabase`来注册数据源分片键值
59+
- 使用`HintShardingValueManager.registerShardingValueOfTable`来注册表分片键值
60+
61+
每种分片键值注册方法中有两个重载方法,参数较短的方法可以简化相等条件的分片值注入。
62+
63+
### 清除注册的分片键值
64+
由于分片键值保存在`ThreadLocal`中,所以需要在操作结束的使用调用`HintShardingValueManager.clear()`来清除`ThreadLocal`中的内容。
65+
如果你没有调用该方法,那么在该线程被复用时(线程池场景),`HintShardingValueManager.init()`被调用将抛出`CAN NOT init repeatedly`异常。
66+
67+
__建议使用`try-finally`或者`AOP`编程的方式来调用清除方法__
68+
69+
70+
71+
72+

sharding-jdbc-doc/content/post/release_notes.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ weight = 1
77
# Release Notes
88

99
## 1.0.1-snapshot
10-
1.增加使用ThreadLocal方式动态生成分区键值的方式进行SQL路由的功能
10+
功能提升:
11+
12+
1. 增加使用暗示(Hint)方式注册分片键值的方式进行SQL路由的功能
13+
14+
bug修改:
1115

1216
1. 修正JPA与Sharding-JDBC的兼容问题。JPA会自动增加SELECT的列别名,导致ORDER BY只能通过别名,而非列名称获取ResultSet的数据。
1317
1. 修正[issue #11](https://github.com/dangdangdotcom/sharding-jdbc/issues/11) count函数在某些情况下返回不正确

sharding-jdbc-doc/content/post/user_guide.md

+2
Original file line numberDiff line numberDiff line change
@@ -385,3 +385,5 @@ String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.orde
385385
}
386386
```
387387
该数据源与普通数据源完全相同,你可以通过上例的API形式来使用,也可以将其配置在Spring,Hibernate等框架中使用。
388+
389+
> 如果希望不依赖于表中的列传入分片键值,参考:[基于暗示的分片键值注册方法](../hint_shardingvalue)

sharding-jdbc-example/sharding-jdbc-example-jdbc/src/main/java/com/dangdang/ddframe/rdb/sharding/example/jdbc/Main.java

+25-3
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,9 @@
2424
import java.util.Arrays;
2525
import java.util.HashMap;
2626
import java.util.Map;
27-
2827
import javax.sql.DataSource;
2928

30-
import org.apache.commons.dbcp.BasicDataSource;
31-
29+
import com.dangdang.ddframe.rdb.sharding.api.HintShardingValueManager;
3230
import com.dangdang.ddframe.rdb.sharding.api.ShardingDataSource;
3331
import com.dangdang.ddframe.rdb.sharding.api.rule.BindingTableRule;
3432
import com.dangdang.ddframe.rdb.sharding.api.rule.DataSourceRule;
@@ -38,6 +36,7 @@
3836
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy;
3937
import com.dangdang.ddframe.rdb.sharding.example.jdbc.algorithm.ModuloDatabaseShardingAlgorithm;
4038
import com.dangdang.ddframe.rdb.sharding.example.jdbc.algorithm.ModuloTableShardingAlgorithm;
39+
import org.apache.commons.dbcp.BasicDataSource;
4140
// CHECKSTYLE:OFF
4241
public final class Main {
4342

@@ -47,6 +46,8 @@ public static void main(final String[] args) throws SQLException {
4746
printSimpleSelect(dataSource);
4847
System.out.println("--------------");
4948
printGroupBy(dataSource);
49+
System.out.println("--------------");
50+
printHintSimpleSelect(dataSource);
5051
}
5152

5253
private static void printSimpleSelect(final DataSource dataSource) throws SQLException {
@@ -79,6 +80,27 @@ private static void printGroupBy(final DataSource dataSource) throws SQLExceptio
7980
}
8081
}
8182

83+
private static void printHintSimpleSelect(final DataSource dataSource) throws SQLException {
84+
String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id";
85+
86+
try (
87+
Connection conn = dataSource.getConnection();
88+
PreparedStatement pstmt = conn.prepareStatement(sql)) {
89+
HintShardingValueManager.init();
90+
HintShardingValueManager.registerShardingValueOfDatabase("t_order", "user_id", 10);
91+
HintShardingValueManager.registerShardingValueOfTable("t_order", "order_id", 1001);
92+
try (ResultSet rs = pstmt.executeQuery()) {
93+
while (rs.next()) {
94+
System.out.println(rs.getInt(1));
95+
System.out.println(rs.getInt(2));
96+
System.out.println(rs.getInt(3));
97+
}
98+
}
99+
} finally {
100+
HintShardingValueManager.clear();
101+
}
102+
}
103+
82104
private static ShardingDataSource getShardingDataSource() throws SQLException {
83105
DataSourceRule dataSourceRule = new DataSourceRule(createDataSourceMap());
84106
TableRule orderTableRule = new TableRule("t_order", Arrays.asList("t_order_0", "t_order_1"), dataSourceRule);

0 commit comments

Comments
 (0)