Skip to content

Commit

Permalink
fix #89
Browse files Browse the repository at this point in the history
  • Loading branch information
terrymanu committed Jun 1, 2016
1 parent bf433b1 commit 4b13df7
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public final class HintManager implements AutoCloseable {

private final Map<ShardingKey, ShardingValue<?>> tableShardingValues = new HashMap<>();

@Getter
private boolean shardingHint;

@Getter
private boolean masterRouteOnly;

Expand Down Expand Up @@ -80,6 +83,7 @@ public void addDatabaseShardingValue(final String logicTable, final String shard
* @param values 分片值
*/
public void addDatabaseShardingValue(final String logicTable, final String shardingColumn, final Condition.BinaryOperator binaryOperator, final Comparable<?>... values) {
shardingHint = true;
databaseShardingValues.put(new ShardingKey(logicTable, shardingColumn), getShardingValue(logicTable, shardingColumn, binaryOperator, values));
}

Expand All @@ -105,6 +109,7 @@ public void addTableShardingValue(final String logicTable, final String sharding
* @param values 分片值
*/
public void addTableShardingValue(final String logicTable, final String shardingColumn, final Condition.BinaryOperator binaryOperator, final Comparable<?>... values) {
shardingHint = true;
tableShardingValues.put(new ShardingKey(logicTable, shardingColumn), getShardingValue(logicTable, shardingColumn, binaryOperator, values));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ public static void setHintManager(final HintManager hintManager) {
* 判断当前线程是否使用线索分片.
* @return 当前线程是否使用线索分片
*/
public static boolean isUseHint() {
return null != HINT_MANAGER_HOLDER.get();
public static boolean isUseShardingHint() {
return null != HINT_MANAGER_HOLDER.get() && HINT_MANAGER_HOLDER.get().isShardingHint();
}

/**
Expand All @@ -59,7 +59,7 @@ public static boolean isUseHint() {
* @return 分库分片键值
*/
public static Optional<ShardingValue<?>> getDatabaseShardingValue(final ShardingKey shardingKey) {
return isUseHint() ? Optional.<ShardingValue<?>>fromNullable(HINT_MANAGER_HOLDER.get().getDatabaseShardingValue(shardingKey)) : Optional.<ShardingValue<?>>absent();
return isUseShardingHint() ? Optional.<ShardingValue<?>>fromNullable(HINT_MANAGER_HOLDER.get().getDatabaseShardingValue(shardingKey)) : Optional.<ShardingValue<?>>absent();
}

/**
Expand All @@ -69,7 +69,7 @@ public static Optional<ShardingValue<?>> getDatabaseShardingValue(final Sharding
* @return 分表分片键值
*/
public static Optional<ShardingValue<?>> getTableShardingValue(final ShardingKey shardingKey) {
return isUseHint() ? Optional.<ShardingValue<?>>fromNullable(HINT_MANAGER_HOLDER.get().getTableShardingValue(shardingKey)) : Optional.<ShardingValue<?>>absent();
return isUseShardingHint() ? Optional.<ShardingValue<?>>fromNullable(HINT_MANAGER_HOLDER.get().getTableShardingValue(shardingKey)) : Optional.<ShardingValue<?>>absent();
}

/**
Expand All @@ -78,7 +78,18 @@ public static Optional<ShardingValue<?>> getTableShardingValue(final ShardingKey
* @return 是否数据库操作只路由至主库
*/
public static boolean isMasterRouteOnly() {
return isUseHint() ? HINT_MANAGER_HOLDER.get().isMasterRouteOnly() : false;
return null != HINT_MANAGER_HOLDER.get() && HINT_MANAGER_HOLDER.get().isMasterRouteOnly();
}

/**
* 设置数据库操作只路由至主库.
*/
public static void setMasterRouteOnly() {
if (null != HINT_MANAGER_HOLDER.get()) {
HINT_MANAGER_HOLDER.get().setMasterRouteOnly();
} else {
HintManager.getInstance().setMasterRouteOnly();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,6 @@
@RequiredArgsConstructor
public final class MasterSlaveDataSource extends AbstractDataSourceAdapter {

private static final ThreadLocal<Boolean> WAS_UPDATED = new ThreadLocal<Boolean>() {

@Override
protected Boolean initialValue() {
return false;
}
};

private final String name;

private final DataSource masterDataSource;
Expand All @@ -61,8 +53,8 @@ protected Boolean initialValue() {
* @return 主或从节点的数据源
*/
public DataSource getDataSource(final SQLStatementType sqlStatementType) {
if (SQLStatementType.SELECT != sqlStatementType || WAS_UPDATED.get() || HintManagerHolder.isMasterRouteOnly()) {
WAS_UPDATED.set(true);
if (SQLStatementType.SELECT != sqlStatementType || HintManagerHolder.isMasterRouteOnly()) {
HintManagerHolder.setMasterRouteOnly();
return masterDataSource;
}
return slaveLoadBalanceStrategy.getDataSource(name, slaveDataSources);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public SingleRoutingResult route() {
private Collection<String> routeDataSources() {
DatabaseShardingStrategy strategy = shardingRule.getDatabaseShardingStrategy(tableRule);
List<ShardingValue<?>> shardingValues;
if (HintManagerHolder.isUseHint()) {
if (HintManagerHolder.isUseShardingHint()) {
shardingValues = getDatabaseShardingValuesFromHint(strategy.getShardingColumns());
} else {
shardingValues = getShardingValues(strategy.getShardingColumns());
Expand All @@ -115,7 +115,7 @@ private Collection<String> routeDataSources() {
private Collection<String> routeTables(final Collection<String> routedDataSources) {
TableShardingStrategy strategy = shardingRule.getTableShardingStrategy(tableRule);
List<ShardingValue<?>> shardingValues;
if (HintManagerHolder.isUseHint()) {
if (HintManagerHolder.isUseShardingHint()) {
shardingValues = getTableShardingValuesFromHint(strategy.getShardingColumns());
} else {
shardingValues = getShardingValues(strategy.getShardingColumns());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.dangdang.ddframe.rdb.sharding.jdbc.MasterSlaveDataSource;
import com.dangdang.ddframe.rdb.sharding.jdbc.ShardingDataSource;
import org.junit.After;
import org.junit.Before;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -46,9 +46,7 @@ public abstract class AbstractShardingMasterSlaveDBUnitTest extends AbstractDBUn
@Before
@After
public void reset() throws NoSuchFieldException, IllegalAccessException {
Field field = MasterSlaveDataSource.class.getDeclaredField("WAS_UPDATED");
field.setAccessible(true);
((ThreadLocal) field.get(MasterSlaveDataSource.class)).remove();
HintManagerHolder.clear();
}

@Override
Expand Down Expand Up @@ -103,16 +101,26 @@ protected List<String> getDataSetFiles() {

protected final ShardingDataSource getShardingDataSource() {
Map<String, DataSource> masterSlaveDataSourceMap = createDataSourceMap(dataSourceName);
MasterSlaveDataSource masterSlaveDs0 = new MasterSlaveDataSource("ms_0", masterSlaveDataSourceMap.get("dataSource_master_0"), Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_0")));
MasterSlaveDataSource masterSlaveDs1 = new MasterSlaveDataSource("ms_1", masterSlaveDataSourceMap.get("dataSource_master_1"), Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_1")));
MasterSlaveDataSource masterSlaveDs2 = new MasterSlaveDataSource("ms_2", masterSlaveDataSourceMap.get("dataSource_master_2"), Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_2")));
MasterSlaveDataSource masterSlaveDs3 = new MasterSlaveDataSource("ms_3", masterSlaveDataSourceMap.get("dataSource_master_3"), Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_3")));
MasterSlaveDataSource masterSlaveDs4 = new MasterSlaveDataSource("ms_4", masterSlaveDataSourceMap.get("dataSource_master_4"), Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_4")));
MasterSlaveDataSource masterSlaveDs5 = new MasterSlaveDataSource("ms_5", masterSlaveDataSourceMap.get("dataSource_master_5"), Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_5")));
MasterSlaveDataSource masterSlaveDs6 = new MasterSlaveDataSource("ms_6", masterSlaveDataSourceMap.get("dataSource_master_6"), Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_6")));
MasterSlaveDataSource masterSlaveDs7 = new MasterSlaveDataSource("ms_7", masterSlaveDataSourceMap.get("dataSource_master_7"), Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_7")));
MasterSlaveDataSource masterSlaveDs8 = new MasterSlaveDataSource("ms_8", masterSlaveDataSourceMap.get("dataSource_master_8"), Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_8")));
MasterSlaveDataSource masterSlaveDs9 = new MasterSlaveDataSource("ms_9", masterSlaveDataSourceMap.get("dataSource_master_9"), Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_9")));
MasterSlaveDataSource masterSlaveDs0 = new MasterSlaveDataSource("ms_0", masterSlaveDataSourceMap.get("dataSource_master_0"),
Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_0")));
MasterSlaveDataSource masterSlaveDs1 = new MasterSlaveDataSource("ms_1", masterSlaveDataSourceMap.get("dataSource_master_1"),
Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_1")));
MasterSlaveDataSource masterSlaveDs2 = new MasterSlaveDataSource("ms_2", masterSlaveDataSourceMap.get("dataSource_master_2"),
Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_2")));
MasterSlaveDataSource masterSlaveDs3 = new MasterSlaveDataSource("ms_3", masterSlaveDataSourceMap.get("dataSource_master_3"),
Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_3")));
MasterSlaveDataSource masterSlaveDs4 = new MasterSlaveDataSource("ms_4", masterSlaveDataSourceMap.get("dataSource_master_4"),
Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_4")));
MasterSlaveDataSource masterSlaveDs5 = new MasterSlaveDataSource("ms_5", masterSlaveDataSourceMap.get("dataSource_master_5"),
Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_5")));
MasterSlaveDataSource masterSlaveDs6 = new MasterSlaveDataSource("ms_6", masterSlaveDataSourceMap.get("dataSource_master_6"),
Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_6")));
MasterSlaveDataSource masterSlaveDs7 = new MasterSlaveDataSource("ms_7", masterSlaveDataSourceMap.get("dataSource_master_7"),
Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_7")));
MasterSlaveDataSource masterSlaveDs8 = new MasterSlaveDataSource("ms_8", masterSlaveDataSourceMap.get("dataSource_master_8"),
Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_8")));
MasterSlaveDataSource masterSlaveDs9 = new MasterSlaveDataSource("ms_9", masterSlaveDataSourceMap.get("dataSource_master_9"),
Collections.singletonList(masterSlaveDataSourceMap.get("dataSource_slave_9")));
Map<String, DataSource> dataSourceMap = new HashMap<>(10);
dataSourceMap.put("ms_0", masterSlaveDs0);
dataSourceMap.put("ms_1", masterSlaveDs1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.dangdang.ddframe.rdb.integrate.masterslave.pstatement;

import com.dangdang.ddframe.rdb.integrate.masterslave.AbstractShardingMasterSlaveDBUnitTest;
import com.dangdang.ddframe.rdb.sharding.api.HintManager;
import com.dangdang.ddframe.rdb.sharding.jdbc.ShardingDataSource;
import com.dangdang.ddframe.rdb.sharding.parser.result.router.SQLStatementType;
import org.dbunit.DatabaseUnitException;
Expand Down Expand Up @@ -57,6 +58,31 @@ public void assertInsertWithAllPlaceholders() throws SQLException, DatabaseUnitE
assertDataSet("insert", "insert");
}

@Test
public void assertInsertWithHint() throws SQLException, DatabaseUnitException {
String sql = "INSERT INTO `t_order` (`order_id`, `user_id`, `status`) VALUES (?, ?, ?)";
for (int i = 1; i <= 10; i++) {
for (int j = 1; j <= 10; j++) {
try (
Connection connection = shardingDataSource.getConnection();
HintManager hintManager = HintManager.getInstance()
) {
hintManager.addDatabaseShardingValue("t_order", "user_id", j);
hintManager.addTableShardingValue("t_order", "order_id", i);
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, i);
preparedStatement.setInt(2, j);
preparedStatement.setString(3, "insert");
preparedStatement.executeUpdate();
}
}
}
try (HintManager hintManager = HintManager.getInstance()) {
hintManager.setMasterRouteOnly();
assertDataSet("insert", "insert");
}
}

@Test
public void assertInsertWithoutPlaceholder() throws SQLException, DatabaseUnitException {
String sql = "INSERT INTO `t_order` (`order_id`, `user_id`, `status`) VALUES (%s, %s, 'insert')";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.dangdang.ddframe.rdb.integrate.masterslave.pstatement;

import com.dangdang.ddframe.rdb.integrate.masterslave.AbstractShardingMasterSlaveDBUnitTest;
import com.dangdang.ddframe.rdb.sharding.api.HintManager;
import com.dangdang.ddframe.rdb.sharding.jdbc.ShardingDataSource;
import org.dbunit.DatabaseUnitException;
import org.junit.Before;
Expand Down Expand Up @@ -95,4 +96,23 @@ public void assertSelectGroupByWithoutGroupedColumn() throws SQLException, Datab
assertDataSet("integrate/dataset/masterslave/expect/select/SelectGroupByWithBindingTable.xml", getShardingDataSource().getConnection(), "t_order_item", sql, 10, 19, 1000, 1909);
assertDataSet("integrate/dataset/Empty.xml", getShardingDataSource().getConnection(), "t_order_item", sql, 1, 9, 1000, 1909);
}

@Test
public void assertSelectForHint() throws SQLException, DatabaseUnitException {
HintManager hintManager = HintManager.getInstance();
hintManager.addDatabaseShardingValue("t_order", "user_id", 10);
hintManager.addTableShardingValue("t_order", "order_id", 1000);
String sql = "SELECT `t_order`.order_id, `t_order`.user_id, `t_order`.status FROM `t_order` WHERE `t_order`.`user_id` = ? AND `t_order`.`order_id` = ?";
assertDataSet("integrate/dataset/masterslave/expect/select/SelectEqualsWithSingleTable_0.xml", shardingDataSource.getConnection(), "t_order", sql, 10, 1000);
}

@Test
public void assertSelectForHintAndForceMaster() throws SQLException, DatabaseUnitException {
HintManager hintManager = HintManager.getInstance();
hintManager.setMasterRouteOnly();
hintManager.addDatabaseShardingValue("t_order", "user_id", 10);
hintManager.addTableShardingValue("t_order", "order_id", 1000);
String sql = "SELECT `t_order`.order_id, `t_order`.user_id, `t_order`.status FROM `t_order` WHERE `t_order`.`user_id` = ? AND `t_order`.`order_id` = ?";
assertDataSet("integrate/dataset/masterslave/expect/select/SelectEqualsWithSingleMasterTable_0.xml", shardingDataSource.getConnection(), "t_order", sql, 10, 1000);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,65 @@ public void assertSetHintManagerTwice() {
HintManagerHolder.setHintManager(HintManager.getInstance());
}

@Test
public void assertsUseShardingHintWithoutAddShardingColumns() {
assertFalse(HintManagerHolder.isUseShardingHint());
}

@Test
public void assertsUseShardingHintWithoutSetHintManager() {
hintManager.close();
assertFalse(HintManagerHolder.isUseShardingHint());
}

@Test
public void assertsUseShardingHintWithAddShardingColumns() {
hintManager.addDatabaseShardingValue("logicTable", "shardingColumn", 1);
assertTrue(HintManagerHolder.isUseShardingHint());
}

@Test
public void assertGetDatabaseShardingValue() {
hintManager.addDatabaseShardingValue("logicTable", "shardingColumn", 1);
assertTrue(HintManagerHolder.getDatabaseShardingValue(new ShardingKey("logicTable", "shardingColumn")).isPresent());
assertTrue(HintManagerHolder.isUseShardingHint());
}

@Test
public void assertGetTableShardingValue() {
hintManager.addTableShardingValue("logicTable", "shardingColumn", 1);
assertTrue(HintManagerHolder.getTableShardingValue(new ShardingKey("logicTable", "shardingColumn")).isPresent());
assertTrue(HintManagerHolder.isUseShardingHint());
}

@Test
public void assertIsMasterRouteOnlyWithoutSet() {
hintManager.close();
assertFalse(HintManagerHolder.isMasterRouteOnly());
assertFalse(HintManagerHolder.isUseShardingHint());
}

@Test
public void assertIsMasterRouteOnly() {
hintManager.setMasterRouteOnly();
assertTrue(HintManagerHolder.isMasterRouteOnly());
assertFalse(HintManagerHolder.isUseShardingHint());
}

@Test
public void assertSetMasterRouteOnlyWithHint() {
HintManagerHolder.setMasterRouteOnly();
assertTrue(HintManagerHolder.isMasterRouteOnly());
assertFalse(HintManagerHolder.isUseShardingHint());
}

@Test
public void assertSetMasterRouteOnlyWithoutHint() {
hintManager.close();
assertFalse(HintManagerHolder.isMasterRouteOnly());
HintManagerHolder.setMasterRouteOnly();
assertTrue(HintManagerHolder.isMasterRouteOnly());
assertFalse(HintManagerHolder.isUseShardingHint());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
import com.dangdang.ddframe.rdb.sharding.api.HintManager;
import com.dangdang.ddframe.rdb.sharding.api.MasterSlaveDataSourceFactory;
import com.dangdang.ddframe.rdb.sharding.fixture.TestDataSource;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.dangdang.ddframe.rdb.sharding.parser.result.router.SQLStatementType;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
Expand All @@ -48,10 +48,8 @@ public final class MasterSlaveDataSourceTest {

@Before
@After
public void reset() throws NoSuchFieldException, IllegalAccessException {
Field field = MasterSlaveDataSource.class.getDeclaredField("WAS_UPDATED");
field.setAccessible(true);
((ThreadLocal) field.get(MasterSlaveDataSource.class)).remove();
public void reset() {
HintManagerHolder.clear();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<dataset>
<t_order order_id="1000" user_id="10" status="init_master" />
</dataset>
7 changes: 3 additions & 4 deletions sharding-jdbc-doc/content/post/master_slave.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ weight = 6

## 支持项
1. 提供了一主多从的读写分离配置,可配合分库分表使用。
1. 同一线程如果有写入操作,以后的读操作均从主库读取,用于保证同一线程中的数据一致性。
1. Spring命名空间。
1. 基于Hint的强制主库路由。

1. 同一`HintManager`生命周期内,如有写入操作,以后的读操作均从主库读取,用于保证同一线程中的数据一致性。
1. `Spring`命名空间。
1. 基于`Hint`的强制主库路由。

## 不支持范围
1. 主库和从库的数据同步。
Expand Down
Loading

0 comments on commit 4b13df7

Please sign in to comment.