提交 4b13df79 编写于 作者: T terrymanu

fix #89

上级 bf433b15
......@@ -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;
......@@ -80,6 +83,7 @@ public final class HintManager implements AutoCloseable {
* @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));
}
......@@ -105,6 +109,7 @@ public final class HintManager implements AutoCloseable {
* @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));
}
......
......@@ -48,8 +48,8 @@ public final class HintManagerHolder {
* 判断当前线程是否使用线索分片.
* @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();
}
/**
......@@ -59,7 +59,7 @@ public final class HintManagerHolder {
* @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();
}
/**
......@@ -69,7 +69,7 @@ public final class HintManagerHolder {
* @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();
}
/**
......@@ -78,7 +78,18 @@ public final class HintManagerHolder {
* @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();
}
}
/**
......
......@@ -38,14 +38,6 @@ import java.util.List;
@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;
......@@ -61,8 +53,8 @@ public final class MasterSlaveDataSource extends AbstractDataSourceAdapter {
* @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);
......
......@@ -100,7 +100,7 @@ public final class SingleTableRouter {
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());
......@@ -115,7 +115,7 @@ public final class SingleTableRouter {
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());
......
......@@ -26,13 +26,13 @@ import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
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;
......@@ -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
......@@ -103,16 +101,26 @@ public abstract class AbstractShardingMasterSlaveDBUnitTest extends AbstractDBUn
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);
......
......@@ -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;
......@@ -57,6 +58,31 @@ public final class ShardingMasterSlaveForPStatementWithDMLTest extends AbstractS
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')";
......
......@@ -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;
......@@ -95,4 +96,23 @@ public class ShardingMasterSlaveForPStatementWithSelectTest extends AbstractShar
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);
}
}
......@@ -38,28 +38,65 @@ public final class HintManagerHolderTest {
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
......
......@@ -20,13 +20,13 @@ package com.dangdang.ddframe.rdb.sharding.jdbc;
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;
......@@ -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
......
......@@ -10,10 +10,9 @@ weight = 6
## 支持项
1. 提供了一主多从的读写分离配置,可配合分库分表使用。
1. 同一线程如果有写入操作,以后的读操作均从主库读取,用于保证同一线程中的数据一致性。
1. Spring命名空间。
1. 基于Hint的强制主库路由。
1. 同一`HintManager`生命周期内,如有写入操作,以后的读操作均从主库读取,用于保证同一线程中的数据一致性。
1. `Spring`命名空间。
1. 基于`Hint`的强制主库路由。
## 不支持范围
1. 主库和从库的数据同步。
......
......@@ -8,6 +8,10 @@ weight = 1
## 1.3.1-SNAPSHOT
### 缺陷修正
1. [ISSUE #89](https://github.com/dangdangdotcom/sharding-jdbc/issues/89) 读写分离和分片的hint一起使用导致冲突
## 1.3.0
### 新功能
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册