diff --git a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/hint/HintManagerHolder.java b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/hint/HintManagerHolder.java index d08d93db36e80..47ff6350dd9e6 100644 --- a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/hint/HintManagerHolder.java +++ b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/hint/HintManagerHolder.java @@ -81,17 +81,6 @@ public static boolean isMasterRouteOnly() { 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(); - } - } - /** * 清理线索分片管理器的本地线程持有者. */ diff --git a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/MasterSlaveDataSource.java b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/MasterSlaveDataSource.java index b3bff3b318558..d47857d81a335 100644 --- a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/MasterSlaveDataSource.java +++ b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/MasterSlaveDataSource.java @@ -38,6 +38,14 @@ @RequiredArgsConstructor public final class MasterSlaveDataSource extends AbstractDataSourceAdapter { + private static final ThreadLocal DML_FLAG = new ThreadLocal() { + + @Override + protected Boolean initialValue() { + return false; + } + }; + private final String name; private final DataSource masterDataSource; @@ -53,8 +61,8 @@ public final class MasterSlaveDataSource extends AbstractDataSourceAdapter { * @return 主或从节点的数据源 */ public DataSource getDataSource(final SQLStatementType sqlStatementType) { - if (SQLStatementType.SELECT != sqlStatementType || HintManagerHolder.isMasterRouteOnly()) { - HintManagerHolder.setMasterRouteOnly(); + if (SQLStatementType.SELECT != sqlStatementType || DML_FLAG.get() || HintManagerHolder.isMasterRouteOnly()) { + DML_FLAG.set(true); return masterDataSource; } return slaveLoadBalanceStrategy.getDataSource(name, slaveDataSources); @@ -79,4 +87,11 @@ String getDatabaseProductName() throws SQLException { public Connection getConnection() throws SQLException { throw new UnsupportedOperationException("Master slave data source cannot support get connection directly."); } + + /** + * 重置更新标记. + */ + public static void resetDMLFlag() { + DML_FLAG.remove(); + } } diff --git a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/ShardingConnection.java b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/ShardingConnection.java index 17bbe32236b5d..b3ce33dfa8bb9 100644 --- a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/ShardingConnection.java +++ b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/ShardingConnection.java @@ -18,6 +18,7 @@ package com.dangdang.ddframe.rdb.sharding.jdbc; import com.codahale.metrics.Timer.Context; +import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder; import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractConnectionAdapter; import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext; import com.dangdang.ddframe.rdb.sharding.parser.result.router.SQLStatementType; @@ -132,4 +133,11 @@ public Statement createStatement(final int resultSetType, final int resultSetCon public Collection getConnections() { return connectionMap.values(); } + + @Override + public void close() throws SQLException { + super.close(); + HintManagerHolder.clear(); + MasterSlaveDataSource.resetDMLFlag(); + } } diff --git a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/adapter/AbstractConnectionAdapter.java b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/adapter/AbstractConnectionAdapter.java index 9846b93f7ab33..2092614342283 100644 --- a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/adapter/AbstractConnectionAdapter.java +++ b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/jdbc/adapter/AbstractConnectionAdapter.java @@ -17,15 +17,15 @@ package com.dangdang.ddframe.rdb.sharding.jdbc.adapter; +import com.dangdang.ddframe.rdb.sharding.jdbc.unsupported.AbstractUnsupportedOperationConnection; +import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext; + import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; import java.util.Collection; -import com.dangdang.ddframe.rdb.sharding.jdbc.unsupported.AbstractUnsupportedOperationConnection; -import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext; - /** * 数据库连接适配类. * @@ -75,7 +75,7 @@ public final void rollback() throws SQLException { } @Override - public final void close() throws SQLException { + public void close() throws SQLException { for (Connection each : getConnections()) { each.close(); } diff --git a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/AbstractShardingMasterSlaveDBUnitTest.java b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/AbstractShardingMasterSlaveDBUnitTest.java index 724da9710e036..fe36455a63040 100644 --- a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/AbstractShardingMasterSlaveDBUnitTest.java +++ b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/AbstractShardingMasterSlaveDBUnitTest.java @@ -47,6 +47,7 @@ public abstract class AbstractShardingMasterSlaveDBUnitTest extends AbstractDBUn @After public void reset() throws NoSuchFieldException, IllegalAccessException { HintManagerHolder.clear(); + MasterSlaveDataSource.resetDMLFlag(); } @Override diff --git a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/pstatement/ShardingMasterSlaveForPStatementWithDMLTest.java b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/pstatement/ShardingMasterSlaveForPStatementWithDMLTest.java index fecfab6e9e7d6..db3da99c19543 100644 --- a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/pstatement/ShardingMasterSlaveForPStatementWithDMLTest.java +++ b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/pstatement/ShardingMasterSlaveForPStatementWithDMLTest.java @@ -181,7 +181,7 @@ protected void assertDataSet(final String expectedDataSetPattern, final String s for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { assertDataSet(String.format("integrate/dataset/masterslave/expect/%s/master_%s.xml", expectedDataSetPattern, i), - shardingDataSource.getConnection().getConnection(String.format("ms_%s", i), SQLStatementType.SELECT), + shardingDataSource.getConnection().getConnection(String.format("ms_%s", i), SQLStatementType.INSERT), String.format("t_order_%s", j), String.format("SELECT * FROM `t_order_%s` WHERE `status`=?", j), status); } } diff --git a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/statement/ShardingMasterSlaveForStatementWithDMLTest.java b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/statement/ShardingMasterSlaveForStatementWithDMLTest.java index a06e9354cf0ad..25e216851ecd4 100644 --- a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/statement/ShardingMasterSlaveForStatementWithDMLTest.java +++ b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/integrate/masterslave/statement/ShardingMasterSlaveForStatementWithDMLTest.java @@ -84,7 +84,7 @@ protected void assertDataSet(final String expectedDataSetPattern, final String s for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { assertDataSet(String.format("integrate/dataset/masterslave/expect/%s/master_%s.xml", expectedDataSetPattern, i), - shardingDataSource.getConnection().getConnection(String.format("ms_%s", i), SQLStatementType.SELECT), + shardingDataSource.getConnection().getConnection(String.format("ms_%s", i), SQLStatementType.INSERT), String.format("t_order_%s", j), String.format("SELECT * FROM `t_order_%s` WHERE `status`=?", j), status); } } diff --git a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/executor/PreparedStatementExecutorTest.java b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/executor/PreparedStatementExecutorTest.java index aad9ec5e12f01..d7a60de6dc27b 100644 --- a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/executor/PreparedStatementExecutorTest.java +++ b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/executor/PreparedStatementExecutorTest.java @@ -121,7 +121,7 @@ public void assertExecuteQueryForSinglePreparedStatementFailure() throws SQLExce SQLException exp = new SQLException(); when(preparedStatement.executeQuery()).thenThrow(exp); PreparedStatementExecutor actual = new PreparedStatementExecutor(executorEngine, Collections.singleton(wrapper)); - assertThat(actual.executeQuery(), is(Collections.singletonList(((ResultSet) null)))); + assertThat(actual.executeQuery(), is(Collections.singletonList((ResultSet) null))); verify(preparedStatement).executeQuery(); verify(eventCaller, times(2)).verifyDataSource("ds_0"); verify(eventCaller, times(2)).verifySQL("SELECT * FROM dual"); diff --git a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/hint/HintManagerHolderTest.java b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/hint/HintManagerHolderTest.java index f278db8d81afc..a3c0547dcad77 100644 --- a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/hint/HintManagerHolderTest.java +++ b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/hint/HintManagerHolderTest.java @@ -83,22 +83,6 @@ public void assertIsMasterRouteOnly() { 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 public void assertClear() { hintManager.addDatabaseShardingValue("logicTable", "shardingColumn", 1); diff --git a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/jdbc/MasterSlaveDataSourceTest.java b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/jdbc/MasterSlaveDataSourceTest.java index ce78dc9f046fa..6cee27ce5ed0f 100644 --- a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/jdbc/MasterSlaveDataSourceTest.java +++ b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/jdbc/MasterSlaveDataSourceTest.java @@ -50,6 +50,7 @@ public final class MasterSlaveDataSourceTest { @After public void reset() { HintManagerHolder.clear(); + MasterSlaveDataSource.resetDMLFlag(); } @Test @@ -121,4 +122,12 @@ private Connection mockConnection(final String dataBaseProductName) throws SQLEx public void assertGetConnection() throws SQLException { masterSlaveDataSource.getConnection(); } + + @Test + public void assertResetDMLFlag() { + assertThat(masterSlaveDataSource.getDataSource(SQLStatementType.INSERT), is(masterDataSource)); + assertThat(masterSlaveDataSource.getDataSource(SQLStatementType.SELECT), is(masterDataSource)); + MasterSlaveDataSource.resetDMLFlag(); + assertThat(masterSlaveDataSource.getDataSource(SQLStatementType.SELECT), is(slaveDataSource)); + } } diff --git a/sharding-jdbc-doc/content/post/master_slave.md b/sharding-jdbc-doc/content/post/master_slave.md index 0c9a51a8d9e0f..289fcb8130d60 100644 --- a/sharding-jdbc-doc/content/post/master_slave.md +++ b/sharding-jdbc-doc/content/post/master_slave.md @@ -10,7 +10,7 @@ weight = 6 ## 支持项 1. 提供了一主多从的读写分离配置,可配合分库分表使用。 -1. 同一`HintManager`生命周期内,如有写入操作,以后的读操作均从主库读取,用于保证同一线程中的数据一致性。 +1. 同一线程且同一数据库连接内,如有写入操作,以后的读操作均从主库读取,用于保证数据一致性。 1. `Spring`命名空间。 1. 基于`Hint`的强制主库路由。 diff --git a/sharding-jdbc-doc/content/post/release_notes.md b/sharding-jdbc-doc/content/post/release_notes.md index b7eea0e5aa2ae..bc756f786780e 100644 --- a/sharding-jdbc-doc/content/post/release_notes.md +++ b/sharding-jdbc-doc/content/post/release_notes.md @@ -11,11 +11,12 @@ weight = 1 ### 功能提升 1. [ISSUE #91](https://github.com/dangdangdotcom/sharding-jdbc/issues/91) 开放对Statement.getGeneratedKeys的支持,可返回原生的数据库自增主键 -1. [ISSUE #91](https://github.com/dangdangdotcom/sharding-jdbc/issues/92) 查询类DQL语句事件发送 +1. [ISSUE #92](https://github.com/dangdangdotcom/sharding-jdbc/issues/92) 查询类DQL语句事件发送 ### 缺陷修正 1. [ISSUE #89](https://github.com/dangdangdotcom/sharding-jdbc/issues/89) 读写分离和分片的hint一起使用导致冲突 +1. [ISSUE #95](https://github.com/dangdangdotcom/sharding-jdbc/issues/95) 同一线程内写入操作后的读操作均从主库读取改为同一线程且同一连接内 ## 1.3.0