diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE deleted file mode 100644 index 297c0c0f8f31f..0000000000000 --- a/.github/ISSUE_TEMPLATE +++ /dev/null @@ -1,19 +0,0 @@ -For English only, other languages we will close it directly. - -Please answer these questions before submitting your issue. Thanks! - -Before submit a new issue, please check existed issue first, to make sure your issue is not a duplicated one. - -### Which version of Sharding-Sphere do you using? - -### Which project do you using? Sharding-JDBC or Sharding-Proxy? - -### Expected behavior - -### Actual behavior - -### Reason analyze - -### Steps to reproduce the behavior, such as: SQL to execute, sharding rule configuration, when exception occur etc - -### For bug report, please *MUST* provide the reproduce example codes (such as a github link). diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000000000..d604eb9ef09fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,32 @@ +--- +name: "\U0001F41B Bug Report" +about: Something isn't working as expected +--- + +## Bug Report + +**For English only**, other languages will not accept. + +Before report a bug, make sure you have: + +- Searched open and closed [GitHub issues](https://github.com/sharding-sphere/sharding-sphere/issues). +- Read documentation: [Sharding-Sphere Doc](http://shardingsphere.io/document/current/en/overview/). + +Please pay attention on issues you submitted, because we maybe need more details. +If no response **more than 7 days** and we cannot reproduce it on current information, we will **close it**. + +Please answer these questions before submitting your issue. Thanks! + +### Which version of Sharding-Sphere did you use? + +### Which project did you use? Sharding-JDBC or Sharding-Proxy? + +### Expected behavior + +### Actual behavior + +### Reason analyze (If you can) + +### Steps to reproduce the behavior, such as: SQL to execute, sharding rule configuration, when exception occur etc. + +### Example codes for reproduce this issue (such as a github link). diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 0000000000000..293b6715912d4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,17 @@ +--- +name: "\U0001F680 Feature Request" +about: I have a suggestion +--- + +## Feature Request + +**For English only**, other languages will not accept. + +Please pay attention on issues you submitted, because we maybe need more details. +If no response **more than 7 days** and we cannot make decision by current information, we will **close it**. + +Please answer these questions before submitting your issue. Thanks! + +### Is your feature request related to a problem? + +### Describe the feature you would like. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000000000..6788c1bc58196 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,17 @@ +--- +name: "\U0001F914 Question" +about: Usage question that isn't answered in docs or discussion +--- + +## Question + +**For English only**, other languages will not accept. + +Before asking a question, make sure you have: + +- Googled your question. +- Searched open and closed [GitHub issues](https://github.com/sharding-sphere/sharding-sphere/issues). +- Read documentation: [Sharding-Sphere Doc](http://shardingsphere.io/document/current/en/overview/). + +Please pay attention on issues you submitted, because we maybe need more details. +If no response **more than 7 days** and we cannot reproduce it on current information, we will **close it**. diff --git a/sharding-core/src/main/java/io/shardingsphere/core/constant/properties/ShardingPropertiesConstant.java b/sharding-core/src/main/java/io/shardingsphere/core/constant/properties/ShardingPropertiesConstant.java index de4a9bb2d2ef3..744ae1d6411e3 100644 --- a/sharding-core/src/main/java/io/shardingsphere/core/constant/properties/ShardingPropertiesConstant.java +++ b/sharding-core/src/main/java/io/shardingsphere/core/constant/properties/ShardingPropertiesConstant.java @@ -17,7 +17,6 @@ package io.shardingsphere.core.constant.properties; -import io.shardingsphere.core.constant.ConnectionMode; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -65,23 +64,6 @@ public enum ShardingPropertiesConstant { */ EXECUTOR_SIZE("executor.size", String.valueOf(0), int.class), - /** - * Connection mode of connected to databases. - * - *

- * MEMORY_STRICTLY: - * Sharding-Sphere holds as many connections as the count of actual tables routed in a database. - * The benefit of this approach is saving memory for Proxy by Stream ResultSet. - *

- * - *

- * CONNECTION_STRICTLY: - * harding-Sphere will release connections after get the overall rows from the ResultSet. - * Meanwhile, the cost of the memory will be increased. - *

- */ - CONNECTION_MODE("connection.mode", ConnectionMode.MEMORY_STRICTLY.name(), String.class), - MAX_CONNECTIONS_SIZE_PER_QUERY("max.connections.size.per.query", String.valueOf(1), int.class), PROXY_TRANSACTION_ENABLED("proxy.transaction.enabled", String.valueOf(Boolean.FALSE), boolean.class), diff --git a/sharding-core/src/main/java/io/shardingsphere/core/event/executor/SQLExecutionEventFactory.java b/sharding-core/src/main/java/io/shardingsphere/core/event/executor/SQLExecutionEventFactory.java index b28c776de5fa3..1353bbaa03efe 100644 --- a/sharding-core/src/main/java/io/shardingsphere/core/event/executor/SQLExecutionEventFactory.java +++ b/sharding-core/src/main/java/io/shardingsphere/core/event/executor/SQLExecutionEventFactory.java @@ -18,7 +18,7 @@ package io.shardingsphere.core.event.executor; import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; +import io.shardingsphere.core.executor.StatementExecuteUnit; import io.shardingsphere.core.metadata.datasource.DataSourceMetaData; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -38,18 +38,18 @@ public final class SQLExecutionEventFactory { * Create SQL execution event. * * @param sqlType SQL type - * @param sqlExecuteUnit SQL execute unit + * @param statementExecuteUnit SQL execute unit * @param parameters parameters * @param dataSourceMetaData data source meta data * @return SQL execution event */ - public static SQLExecutionEvent createEvent(final SQLType sqlType, final SQLExecuteUnit sqlExecuteUnit, final List parameters, final DataSourceMetaData dataSourceMetaData) { + public static SQLExecutionEvent createEvent(final SQLType sqlType, final StatementExecuteUnit statementExecuteUnit, final List parameters, final DataSourceMetaData dataSourceMetaData) { if (SQLType.DQL == sqlType) { - return new DQLExecutionEvent(sqlExecuteUnit.getRouteUnit(), parameters, dataSourceMetaData); + return new DQLExecutionEvent(statementExecuteUnit.getRouteUnit(), parameters, dataSourceMetaData); } if (SQLType.DML == sqlType) { - return new DMLExecutionEvent(sqlExecuteUnit.getRouteUnit(), parameters, dataSourceMetaData); + return new DMLExecutionEvent(statementExecuteUnit.getRouteUnit(), parameters, dataSourceMetaData); } - return new SQLExecutionEvent(sqlExecuteUnit.getRouteUnit(), parameters, dataSourceMetaData); + return new SQLExecutionEvent(statementExecuteUnit.getRouteUnit(), parameters, dataSourceMetaData); } } diff --git a/sharding-core/src/main/java/io/shardingsphere/core/event/root/RootInvokeFinishEvent.java b/sharding-core/src/main/java/io/shardingsphere/core/event/root/RootInvokeFinishEvent.java deleted file mode 100644 index 13a31b0c3173d..0000000000000 --- a/sharding-core/src/main/java/io/shardingsphere/core/event/root/RootInvokeFinishEvent.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.event.root; - -/** - * Root invoke finish event. - * - * @author zhangyonglun - */ -public final class RootInvokeFinishEvent extends RootInvokeEvent { -} diff --git a/sharding-core/src/main/java/io/shardingsphere/core/event/root/RootInvokeStartEvent.java b/sharding-core/src/main/java/io/shardingsphere/core/event/root/RootInvokeStartEvent.java deleted file mode 100644 index 768ad90a1b63c..0000000000000 --- a/sharding-core/src/main/java/io/shardingsphere/core/event/root/RootInvokeStartEvent.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.event.root; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -/** - * Root invoke start event. - * - * @author zhangyonglun - */ -@RequiredArgsConstructor -@Getter -public final class RootInvokeStartEvent extends RootInvokeEvent { - - private final boolean parallelExecute; -} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/StatementExecuteUnit.java b/sharding-core/src/main/java/io/shardingsphere/core/executor/StatementExecuteUnit.java similarity index 65% rename from sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/StatementExecuteUnit.java rename to sharding-core/src/main/java/io/shardingsphere/core/executor/StatementExecuteUnit.java index 3cb49bfc7c3bf..c4944625c42ea 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/StatementExecuteUnit.java +++ b/sharding-core/src/main/java/io/shardingsphere/core/executor/StatementExecuteUnit.java @@ -15,12 +15,11 @@ *

*/ -package io.shardingsphere.core.executor.statement; +package io.shardingsphere.core.executor; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; +import io.shardingsphere.core.constant.ConnectionMode; import io.shardingsphere.core.routing.RouteUnit; import lombok.Getter; -import lombok.RequiredArgsConstructor; import java.sql.Statement; @@ -28,12 +27,20 @@ * Execute unit for JDBC statement. * * @author zhangliang + * @author panjuan */ -@RequiredArgsConstructor @Getter -public final class StatementExecuteUnit implements SQLExecuteUnit { +public final class StatementExecuteUnit { private final RouteUnit routeUnit; private final Statement statement; + + private final ConnectionMode connectionMode; + + public StatementExecuteUnit(final RouteUnit routeUnit, final Statement statement, final ConnectionMode connectionMode) { + this.routeUnit = routeUnit; + this.statement = statement; + this.connectionMode = connectionMode; + } } diff --git a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/SQLExecuteUnit.java b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/SQLExecuteUnit.java deleted file mode 100644 index 18b2f35e0a27f..0000000000000 --- a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/SQLExecuteUnit.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.executor.sql; - -import io.shardingsphere.core.routing.RouteUnit; - -import java.sql.Statement; - -/** - * SQL execute unit. - * - * @author zhangliang - */ -public interface SQLExecuteUnit { - - /** - * Get route unit. - * - * @return route unit - */ - RouteUnit getRouteUnit(); - - /** - * Get statement. - * - * @return statement - */ - Statement getStatement(); -} diff --git a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/SQLExecuteCallback.java b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/SQLExecuteCallback.java index ae2fbc1e07370..8b0afad0f8fa9 100644 --- a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/SQLExecuteCallback.java +++ b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/SQLExecuteCallback.java @@ -25,7 +25,7 @@ import io.shardingsphere.core.event.executor.SQLExecutionEventFactory; import io.shardingsphere.core.executor.ShardingExecuteCallback; import io.shardingsphere.core.executor.ShardingGroupExecuteCallback; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; +import io.shardingsphere.core.executor.StatementExecuteUnit; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; import io.shardingsphere.core.metadata.datasource.DataSourceMetaData; @@ -47,7 +47,7 @@ * @param class type of return value */ @RequiredArgsConstructor -public abstract class SQLExecuteCallback implements ShardingExecuteCallback, ShardingGroupExecuteCallback { +public abstract class SQLExecuteCallback implements ShardingExecuteCallback, ShardingGroupExecuteCallback { private final DatabaseType databaseType; @@ -60,38 +60,38 @@ public abstract class SQLExecuteCallback implements ShardingExecuteCallback execute(final Collection sqlExecuteUnits) throws SQLException { + public final Collection execute(final Collection statementExecuteUnits) throws SQLException { Collection result = new LinkedList<>(); - for (SQLExecuteUnit each : sqlExecuteUnits) { + for (StatementExecuteUnit each : statementExecuteUnits) { result.add(execute0(each)); } return result; } - private T execute0(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { + private T execute0(final StatementExecuteUnit statementExecuteUnit) throws SQLException { ExecutorExceptionHandler.setExceptionThrown(isExceptionThrown); ExecutorDataMap.setDataMap(dataMap); - List> parameterSets = sqlExecuteUnit.getRouteUnit().getSqlUnit().getParameterSets(); - DataSourceMetaData dataSourceMetaData = DataSourceMetaDataFactory.newInstance(databaseType, sqlExecuteUnit.getStatement().getConnection().getMetaData().getURL()); + List> parameterSets = statementExecuteUnit.getRouteUnit().getSqlUnit().getParameterSets(); + DataSourceMetaData dataSourceMetaData = DataSourceMetaDataFactory.newInstance(databaseType, statementExecuteUnit.getStatement().getConnection().getMetaData().getURL()); for (List each : parameterSets) { - shardingEventBus.post(SQLExecutionEventFactory.createEvent(sqlType, sqlExecuteUnit, each, dataSourceMetaData)); + shardingEventBus.post(SQLExecutionEventFactory.createEvent(sqlType, statementExecuteUnit, each, dataSourceMetaData)); } try { - T result = executeSQL(sqlExecuteUnit); + T result = executeSQL(statementExecuteUnit); for (List each : parameterSets) { - SQLExecutionEvent finishEvent = SQLExecutionEventFactory.createEvent(sqlType, sqlExecuteUnit, each, dataSourceMetaData); + SQLExecutionEvent finishEvent = SQLExecutionEventFactory.createEvent(sqlType, statementExecuteUnit, each, dataSourceMetaData); finishEvent.setExecuteSuccess(); shardingEventBus.post(finishEvent); } return result; } catch (final SQLException ex) { for (List each : parameterSets) { - SQLExecutionEvent finishEvent = SQLExecutionEventFactory.createEvent(sqlType, sqlExecuteUnit, each, dataSourceMetaData); + SQLExecutionEvent finishEvent = SQLExecutionEventFactory.createEvent(sqlType, statementExecuteUnit, each, dataSourceMetaData); finishEvent.setExecuteFailure(ex); shardingEventBus.post(finishEvent); } @@ -100,5 +100,5 @@ private T execute0(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { } } - protected abstract T executeSQL(SQLExecuteUnit sqlExecuteUnit) throws SQLException; + protected abstract T executeSQL(StatementExecuteUnit statementExecuteUnit) throws SQLException; } diff --git a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/SQLExecuteTemplate.java b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/SQLExecuteTemplate.java index c130e29adf944..8c930ea6a6a78 100644 --- a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/SQLExecuteTemplate.java +++ b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/SQLExecuteTemplate.java @@ -19,7 +19,7 @@ import io.shardingsphere.core.executor.ShardingExecuteEngine; import io.shardingsphere.core.executor.ShardingExecuteGroup; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; +import io.shardingsphere.core.executor.StatementExecuteUnit; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; import lombok.RequiredArgsConstructor; @@ -44,20 +44,20 @@ public final class SQLExecuteTemplate { /** * Execute. * - * @param sqlExecuteUnits SQL execute units + * @param statementExecuteUnits SQL execute units * @param callback SQL execute callback * @param class type of return value * @return execute result * @throws SQLException SQL exception */ - public List execute(final Collection sqlExecuteUnits, final SQLExecuteCallback callback) throws SQLException { - return execute(sqlExecuteUnits, null, callback); + public List execute(final Collection statementExecuteUnits, final SQLExecuteCallback callback) throws SQLException { + return execute(statementExecuteUnits, null, callback); } /** * Execute. * - * @param sqlExecuteUnits SQL execute units + * @param statementExecuteUnits SQL execute units * @param firstExecuteCallback first SQL execute callback * @param callback SQL execute callback * @param class type of return value @@ -65,16 +65,18 @@ public List execute(final Collection sqlExecute * @throws SQLException SQL exception */ @SuppressWarnings("unchecked") - public List execute(final Collection sqlExecuteUnits, - final SQLExecuteCallback firstExecuteCallback, final SQLExecuteCallback callback) throws SQLException { + public List execute( + final Collection statementExecuteUnits, final SQLExecuteCallback firstExecuteCallback, final SQLExecuteCallback callback) throws SQLException { try { - return executeEngine.execute((Collection) sqlExecuteUnits, firstExecuteCallback, callback); + return executeEngine.execute((Collection) statementExecuteUnits, firstExecuteCallback, callback); } catch (final SQLException ex) { ExecutorExceptionHandler.handleException(ex); return Collections.emptyList(); } } + + /** * Execute group. * @@ -84,7 +86,7 @@ public List execute(final Collection sqlExecute * @return execute result * @throws SQLException SQL exception */ - public List executeGroup(final Collection> sqlExecuteGroups, final SQLExecuteCallback callback) throws SQLException { + public List executeGroup(final Collection> sqlExecuteGroups, final SQLExecuteCallback callback) throws SQLException { return executeGroup(sqlExecuteGroups, null, callback); } @@ -99,7 +101,7 @@ public List executeGroup(final Collection List executeGroup(final Collection> sqlExecuteGroups, + public List executeGroup(final Collection> sqlExecuteGroups, final SQLExecuteCallback firstCallback, final SQLExecuteCallback callback) throws SQLException { try { return executeEngine.groupExecute((Collection) sqlExecuteGroups, firstCallback, callback); @@ -109,3 +111,4 @@ public List executeGroup(final Collection columnLabelAndIndexMap; + private final Multimap columnLabelAndIndexMap; private final Iterator> resultData; @@ -52,8 +52,8 @@ public MemoryQueryResult(final ResultSet resultSet) throws SQLException { resultData = getResultData(resultSet); } - private Map getMetaData(final ResultSetMetaData resultSetMetaData) throws SQLException { - Map result = new HashMap<>(); + private Multimap getMetaData(final ResultSetMetaData resultSetMetaData) throws SQLException { + Multimap result = HashMultimap.create(); for (int columnIndex = 1; columnIndex <= resultSetMetaData.getColumnCount(); columnIndex++) { result.put(resultSetMetaData.getColumnLabel(columnIndex), columnIndex); } @@ -89,7 +89,7 @@ public Object getValue(final int columnIndex, final Class type) { @Override public Object getValue(final String columnLabel, final Class type) { - return currentRow.get(columnLabelAndIndexMap.get(columnLabel)); + return currentRow.get(getIndexByColumnLabel(columnLabel)); } @Override @@ -99,7 +99,7 @@ public Object getCalendarValue(final int columnIndex, final Class type, final @Override public Object getCalendarValue(final String columnLabel, final Class type, final Calendar calendar) { - return currentRow.get(columnLabelAndIndexMap.get(columnLabel)); + return currentRow.get(getIndexByColumnLabel(columnLabel)); } @Override @@ -109,7 +109,7 @@ public InputStream getInputStream(final int columnIndex, final String type) { @Override public InputStream getInputStream(final String columnLabel, final String type) { - return (InputStream) currentRow.get(columnLabelAndIndexMap.get(columnLabel)); + return (InputStream) currentRow.get(getIndexByColumnLabel(columnLabel)); } @Override @@ -124,11 +124,15 @@ public int getColumnCount() { @Override public String getColumnLabel(final int columnIndex) throws SQLException { - for (Entry entry : columnLabelAndIndexMap.entrySet()) { + for (Entry entry : columnLabelAndIndexMap.entries()) { if (columnIndex == entry.getValue()) { return entry.getKey(); } } throw new SQLException("Column index out of range", "9999"); } + + private Integer getIndexByColumnLabel(final String columnLabel) { + return new ArrayList<>(columnLabelAndIndexMap.get(columnLabel)).get(0) - 1; + } } diff --git a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/result/StreamQueryResult.java b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/result/StreamQueryResult.java index 47ebbe87344ee..38354dfc0f5c1 100644 --- a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/result/StreamQueryResult.java +++ b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/execute/result/StreamQueryResult.java @@ -172,6 +172,7 @@ public Object getCalendarValue(final String columnLabel, final Class type, fi throw new SQLException(String.format("Unsupported type: %s", type)); } + @SuppressWarnings("deprecation") @Override public InputStream getInputStream(final int columnIndex, final String type) throws SQLException { switch (type) { @@ -186,6 +187,7 @@ public InputStream getInputStream(final int columnIndex, final String type) thro } } + @SuppressWarnings("deprecation") @Override public InputStream getInputStream(final String columnLabel, final String type) throws SQLException { switch (type) { diff --git a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/prepare/SQLExecutePrepareCallback.java b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/prepare/SQLExecutePrepareCallback.java index f9f4f77bfd597..ba60a15d13be0 100644 --- a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/prepare/SQLExecutePrepareCallback.java +++ b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/prepare/SQLExecutePrepareCallback.java @@ -17,16 +17,19 @@ package io.shardingsphere.core.executor.sql.prepare; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; +import io.shardingsphere.core.constant.ConnectionMode; +import io.shardingsphere.core.executor.StatementExecuteUnit; import io.shardingsphere.core.routing.RouteUnit; import java.sql.Connection; import java.sql.SQLException; +import java.util.List; /** * SQL execute prepare callback. * * @author zhangliang + * @author panjuan */ public interface SQLExecutePrepareCallback { @@ -34,18 +37,20 @@ public interface SQLExecutePrepareCallback { * Get connection. * * @param dataSourceName data source name + * @param connectionSize connection size * @return connection * @throws SQLException SQL exception */ - Connection getConnection(String dataSourceName) throws SQLException; + List getConnections(String dataSourceName, int connectionSize) throws SQLException; /** * Create SQL execute unit. * * @param connection connection * @param routeUnit route unit + * @param connectionMode connection mode * @return SQL execute unit * @throws SQLException SQL exception */ - SQLExecuteUnit createSQLExecuteUnit(Connection connection, RouteUnit routeUnit) throws SQLException; + StatementExecuteUnit createStatementExecuteUnit(Connection connection, RouteUnit routeUnit, ConnectionMode connectionMode) throws SQLException; } diff --git a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/prepare/SQLExecutePrepareTemplate.java b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/prepare/SQLExecutePrepareTemplate.java index e41ca93b21f83..48a10529b3e51 100644 --- a/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/prepare/SQLExecutePrepareTemplate.java +++ b/sharding-core/src/main/java/io/shardingsphere/core/executor/sql/prepare/SQLExecutePrepareTemplate.java @@ -18,8 +18,9 @@ package io.shardingsphere.core.executor.sql.prepare; import com.google.common.collect.Lists; +import io.shardingsphere.core.constant.ConnectionMode; import io.shardingsphere.core.executor.ShardingExecuteGroup; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; +import io.shardingsphere.core.executor.StatementExecuteUnit; import io.shardingsphere.core.routing.RouteUnit; import io.shardingsphere.core.routing.SQLUnit; import lombok.RequiredArgsConstructor; @@ -38,6 +39,7 @@ * * @author zhaojun * @author zhangliang + * @author panjuan */ @RequiredArgsConstructor public final class SQLExecutePrepareTemplate { @@ -52,9 +54,9 @@ public final class SQLExecutePrepareTemplate { * @return statement execute unit groups * @throws SQLException SQL exception */ - public Collection> getExecuteUnitGroups(final Collection routeUnits, final SQLExecutePrepareCallback callback) throws SQLException { + public Collection> getExecuteUnitGroups(final Collection routeUnits, final SQLExecutePrepareCallback callback) throws SQLException { Map> sqlUnitGroups = getSQLUnitGroups(routeUnits); - Collection> result = new LinkedList<>(); + Collection> result = new LinkedList<>(); for (Entry> entry : sqlUnitGroups.entrySet()) { result.addAll(getSQLExecuteGroups(entry.getKey(), entry.getValue(), callback)); } @@ -72,22 +74,28 @@ private Map> getSQLUnitGroups(final Collection return result; } - private List> getSQLExecuteGroups(final String dataSourceName, final List sqlUnits, final SQLExecutePrepareCallback callback) throws SQLException { - List> result = new LinkedList<>(); + private List> getSQLExecuteGroups( + final String dataSourceName, final List sqlUnits, final SQLExecutePrepareCallback callback) throws SQLException { + List> result = new LinkedList<>(); int desiredPartitionSize = Math.max(sqlUnits.size() / maxConnectionsSizePerQuery, 1); - for (List each : Lists.partition(sqlUnits, desiredPartitionSize)) { - // TODO get connection sync to prevent dead lock - result.add(getSQLExecuteGroup(callback.getConnection(dataSourceName), dataSourceName, each, callback)); + List> sqlUnitGroups = Lists.partition(sqlUnits, desiredPartitionSize); + List connections = callback.getConnections(dataSourceName, sqlUnitGroups.size()); + int count = 0; + for (List each : sqlUnitGroups) { + result.add(getSQLExecuteGroup(connections.get(count++), dataSourceName, each, callback)); } return result; } - private ShardingExecuteGroup getSQLExecuteGroup( + private ShardingExecuteGroup getSQLExecuteGroup( final Connection connection, final String dataSourceName, final List sqlUnitGroup, final SQLExecutePrepareCallback callback) throws SQLException { - List result = new LinkedList<>(); + List result = new LinkedList<>(); + ConnectionMode connectionMode = 1 == sqlUnitGroup.size() ? ConnectionMode.MEMORY_STRICTLY : ConnectionMode.CONNECTION_STRICTLY; for (SQLUnit each : sqlUnitGroup) { - result.add(callback.createSQLExecuteUnit(connection, new RouteUnit(dataSourceName, each))); + result.add(callback.createStatementExecuteUnit(connection, new RouteUnit(dataSourceName, each), connectionMode)); } return new ShardingExecuteGroup<>(result); } } + + diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/BatchPreparedStatementExecuteUnit.java b/sharding-core/src/main/java/io/shardingsphere/core/routing/BatchRouteUnit.java similarity index 73% rename from sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/BatchPreparedStatementExecuteUnit.java rename to sharding-core/src/main/java/io/shardingsphere/core/routing/BatchRouteUnit.java index f9726a605b94a..01fe802c4a139 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/BatchPreparedStatementExecuteUnit.java +++ b/sharding-core/src/main/java/io/shardingsphere/core/routing/BatchRouteUnit.java @@ -15,42 +15,44 @@ *

*/ -package io.shardingsphere.core.executor.batch; +package io.shardingsphere.core.routing; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; -import io.shardingsphere.core.routing.RouteUnit; import lombok.AccessLevel; +import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.RequiredArgsConstructor; +import lombok.ToString; -import java.sql.PreparedStatement; import java.util.LinkedHashMap; import java.util.Map; /** - * Execute unit for JDBC prepared statement add batch. + * Batch route unit. * - * @author zhangliang + * @author panjuan */ -@RequiredArgsConstructor @Getter -public final class BatchPreparedStatementExecuteUnit implements SQLExecuteUnit { +@EqualsAndHashCode(of = { "routeUnit" }) +@ToString +public final class BatchRouteUnit { private final RouteUnit routeUnit; - private final PreparedStatement statement; - private final Map jdbcAndActualAddBatchCallTimesMap = new LinkedHashMap<>(); @Getter(AccessLevel.NONE) private int actualCallAddBatchTimes; + public BatchRouteUnit(final RouteUnit routeUnit) { + this.routeUnit = routeUnit; + } + /** * Map times of use JDBC API call addBatch and times of actual call addBatch after route. - * + * * @param jdbcAddBatchTimes times of use JDBC API call addBatch */ public void mapAddBatchCount(final int jdbcAddBatchTimes) { jdbcAndActualAddBatchCallTimesMap.put(jdbcAddBatchTimes, actualCallAddBatchTimes++); } } + diff --git a/sharding-core/src/test/java/io/shardingsphere/core/executor/fixture/ExecutorTestUtil.java b/sharding-core/src/test/java/io/shardingsphere/core/executor/fixture/ExecutorTestUtil.java index 50e4cafa81504..eda7b37998eef 100644 --- a/sharding-core/src/test/java/io/shardingsphere/core/executor/fixture/ExecutorTestUtil.java +++ b/sharding-core/src/test/java/io/shardingsphere/core/executor/fixture/ExecutorTestUtil.java @@ -20,7 +20,6 @@ import io.shardingsphere.core.event.ShardingEventType; import io.shardingsphere.core.event.executor.SQLExecutionEvent; import io.shardingsphere.core.event.root.RootInvokeEvent; -import io.shardingsphere.core.event.root.RootInvokeStartEvent; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -53,7 +52,6 @@ public static void listen(final EventCaller eventCaller, final SQLExecutionEvent * @param event overall execution event */ public static void listen(final EventCaller eventCaller, final RootInvokeEvent event) { - eventCaller.verifyIsParallelExecute(((RootInvokeStartEvent) event).isParallelExecute()); if (ShardingEventType.EXECUTE_FAILURE == event.getEventType()) { eventCaller.verifyException(event.getException()); } diff --git a/sharding-core/src/test/java/io/shardingsphere/core/merger/fixture/TestQueryResult.java b/sharding-core/src/test/java/io/shardingsphere/core/merger/fixture/TestQueryResult.java index e3a6925fdc173..2f4f2538af0e1 100644 --- a/sharding-core/src/test/java/io/shardingsphere/core/merger/fixture/TestQueryResult.java +++ b/sharding-core/src/test/java/io/shardingsphere/core/merger/fixture/TestQueryResult.java @@ -166,6 +166,7 @@ public Object getCalendarValue(final String columnLabel, final Class type, fi throw new SQLException(String.format("Unsupported type: %s", type)); } + @SuppressWarnings("deprecation") @Override public InputStream getInputStream(final int columnIndex, final String type) throws SQLException { switch (type) { @@ -180,6 +181,7 @@ public InputStream getInputStream(final int columnIndex, final String type) thro } } + @SuppressWarnings("deprecation") @Override public InputStream getInputStream(final String columnLabel, final String type) throws SQLException { switch (type) { diff --git a/sharding-core/src/test/java/io/shardingsphere/core/parsing/parser/sql/UpdateStatementParserTest.java b/sharding-core/src/test/java/io/shardingsphere/core/parsing/parser/sql/UpdateStatementParserTest.java index 22c5ebe005573..1ae55b7aee87c 100644 --- a/sharding-core/src/test/java/io/shardingsphere/core/parsing/parser/sql/UpdateStatementParserTest.java +++ b/sharding-core/src/test/java/io/shardingsphere/core/parsing/parser/sql/UpdateStatementParserTest.java @@ -17,57 +17,19 @@ package io.shardingsphere.core.parsing.parser.sql; -import com.google.common.collect.Range; -import io.shardingsphere.core.api.algorithm.sharding.ListShardingValue; -import io.shardingsphere.core.api.algorithm.sharding.RangeShardingValue; import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.ShardingOperator; import io.shardingsphere.core.parsing.SQLParsingEngine; -import io.shardingsphere.core.parsing.parser.context.condition.Column; -import io.shardingsphere.core.parsing.parser.context.condition.Condition; import io.shardingsphere.core.parsing.parser.sql.dml.DMLStatement; import io.shardingsphere.core.rule.ShardingRule; -import org.hamcrest.CoreMatchers; import org.junit.Test; -import java.util.Collections; -import java.util.Iterator; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; public final class UpdateStatementParserTest extends AbstractStatementParserTest { - - @Test - public void parseWithoutParameter() { - ShardingRule shardingRule = createShardingRule(); - SQLParsingEngine statementParser = new SQLParsingEngine(DatabaseType.MySQL, "UPDATE TABLE_XXX xxx SET TABLE_XXX.field1=field1+1,xxx.field2=2 WHERE TABLE_XXX.field4<10 AND" - + " TABLE_XXX.field1=1 AND xxx.field5>10 AND TABLE_XXX.field2 IN (1,3) AND xxx.field6<=10 AND TABLE_XXX.field3 BETWEEN 5 AND 20 AND xxx.field7>=10", shardingRule, null); - DMLStatement updateStatement = (DMLStatement) statementParser.parse(false); - assertUpdateStatementWithoutParameter(updateStatement); - } - - private void assertUpdateStatementWithoutParameter(final DMLStatement updateStatement) { - assertThat(updateStatement.getTables().find("TABLE_XXX").get().getName(), is("TABLE_XXX")); - assertThat(updateStatement.getTables().find("TABLE_XXX").get().getAlias().get(), is("xxx")); - Condition condition1 = updateStatement.getConditions().find(new Column("field1", "TABLE_XXX")).get(); - assertThat(condition1.getOperator(), CoreMatchers.is(ShardingOperator.EQUAL)); - assertThat(((ListShardingValue) condition1.getShardingValue(Collections.emptyList())).getValues().iterator().next(), is((Comparable) 1)); - Condition condition2 = updateStatement.getConditions().find(new Column("field2", "TABLE_XXX")).get(); - assertThat(condition2.getOperator(), is(ShardingOperator.IN)); - Iterator shardingValues2 = ((ListShardingValue) condition2.getShardingValue(Collections.emptyList())).getValues().iterator(); - assertThat(shardingValues2.next(), is((Object) 1)); - assertThat(shardingValues2.next(), is((Object) 3)); - assertFalse(shardingValues2.hasNext()); - Condition condition3 = updateStatement.getConditions().find(new Column("field3", "TABLE_XXX")).get(); - Range shardingValues3 = ((RangeShardingValue) condition3.getShardingValue(Collections.emptyList())).getValueRange(); - assertThat(condition3.getOperator(), is(ShardingOperator.BETWEEN)); - assertThat(shardingValues3.lowerEndpoint(), is((Comparable) 5)); - assertThat(shardingValues3.upperEndpoint(), is((Comparable) 20)); - } - + @Test public void parseWithOr() { ShardingRule shardingRule = createShardingRule(); @@ -82,22 +44,4 @@ private void assertUpdateStatementWitOr(final DMLStatement updateStatement) { assertTrue(updateStatement.getConditions().getOrCondition().getAndConditions().isEmpty()); } - - @Test - public void parseWithSpecialSyntax() { - parseWithSpecialSyntax(DatabaseType.MySQL, "UPDATE `TABLE_XXX` SET `field1`=1 WHERE `field1`=1"); - parseWithSpecialSyntax(DatabaseType.Oracle, "UPDATE /*+ index(field1) */ ONLY TABLE_XXX SET field1=1 WHERE field1=1 RETURN * LOG ERRORS INTO TABLE_LOG"); - parseWithSpecialSyntax(DatabaseType.Oracle, "UPDATE /*+ index(field1) */ ONLY TABLE_XXX SET field1=1 WHERE field1=1 RETURNING *"); - parseWithSpecialSyntax(DatabaseType.Oracle, "UPDATE /*+ index(field1) */ ONLY TABLE_XXX SET field1=1 WHERE field1=1 LOG ERRORS INTO TABLE_LOG"); - } - - private void parseWithSpecialSyntax(final DatabaseType dbType, final String actualSQL) { - ShardingRule shardingRule = createShardingRule(); - DMLStatement updateStatement = (DMLStatement) new SQLParsingEngine(dbType, actualSQL, shardingRule, null).parse(false); - assertThat(updateStatement.getTables().find("TABLE_XXX").get().getName(), is("TABLE_XXX")); - assertFalse(updateStatement.getTables().find("TABLE_XXX").get().getAlias().isPresent()); - Condition condition = updateStatement.getConditions().find(new Column("field1", "TABLE_XXX")).get(); - assertThat(condition.getOperator(), is(ShardingOperator.EQUAL)); - assertThat(((ListShardingValue) condition.getShardingValue(Collections.emptyList())).getValues().iterator().next(), is((Object) 1)); - } } diff --git a/sharding-core/src/test/resources/parser/update.xml b/sharding-core/src/test/resources/parser/update.xml index 44705f42bb519..041fce44f2e17 100644 --- a/sharding-core/src/test/resources/parser/update.xml +++ b/sharding-core/src/test/resources/parser/update.xml @@ -84,4 +84,62 @@ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/AbstractStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/AbstractStatementExecutor.java new file mode 100644 index 0000000000000..5cdbc6170331f --- /dev/null +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/AbstractStatementExecutor.java @@ -0,0 +1,115 @@ +/* + * Copyright 2016-2018 shardingsphere.io. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *

+ */ + +package io.shardingsphere.core.executor; + +import io.shardingsphere.core.constant.DatabaseType; +import io.shardingsphere.core.constant.SQLType; +import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; +import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; +import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareTemplate; +import io.shardingsphere.core.jdbc.core.connection.ShardingConnection; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Abstract statement executor. + * + * @author panjuan + */ +@Getter(AccessLevel.PROTECTED) +public class AbstractStatementExecutor { + + private final DatabaseType databaseType; + + @Getter + private final int resultSetType; + + @Getter + private final int resultSetConcurrency; + + @Getter + private final int resultSetHoldability; + + private final ShardingConnection connection; + + private final SQLExecutePrepareTemplate sqlExecutePrepareTemplate; + + private final SQLExecuteTemplate sqlExecuteTemplate; + + private final Collection connections = new LinkedList<>(); + + @Getter + private final List> parameterSets = new LinkedList<>(); + + @Getter + private final List statements = new LinkedList<>(); + + @Getter + private final List resultSets = new CopyOnWriteArrayList<>(); + + private final Collection> executeGroups = new LinkedList<>(); + + @Getter + @Setter + private SQLType sqlType; + + public AbstractStatementExecutor(final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final ShardingConnection shardingConnection) { + this.databaseType = shardingConnection.getShardingContext().getDatabaseType(); + this.resultSetType = resultSetType; + this.resultSetConcurrency = resultSetConcurrency; + this.resultSetHoldability = resultSetHoldability; + this.connection = shardingConnection; + sqlExecutePrepareTemplate = new SQLExecutePrepareTemplate(connection.getShardingContext().getMaxConnectionsSizePerQuery()); + sqlExecuteTemplate = new SQLExecuteTemplate(connection.getShardingContext().getExecuteEngine()); + } + + @SuppressWarnings("unchecked") + protected final List executeCallback(final SQLExecuteCallback executeCallback) throws SQLException { + return sqlExecuteTemplate.executeGroup((Collection) executeGroups, executeCallback); + } + + /** + * Clear data. + * + * @throws SQLException sql exception + */ + public void clear() throws SQLException { + clearStatements(); + statements.clear(); + parameterSets.clear(); + connections.clear(); + resultSets.clear(); + executeGroups.clear(); + } + + private void clearStatements() throws SQLException { + for (Statement each : getStatements()) { + each.close(); + } + } +} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/BatchPreparedStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/BatchPreparedStatementExecutor.java new file mode 100644 index 0000000000000..fd96f1c1f34a4 --- /dev/null +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/BatchPreparedStatementExecutor.java @@ -0,0 +1,242 @@ +/* + * Copyright 2016-2018 shardingsphere.io. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *

+ */ + +package io.shardingsphere.core.executor; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterators; +import com.google.common.collect.Lists; +import io.shardingsphere.core.constant.ConnectionMode; +import io.shardingsphere.core.constant.DatabaseType; +import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; +import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; +import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; +import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareCallback; +import io.shardingsphere.core.jdbc.core.connection.ShardingConnection; +import io.shardingsphere.core.routing.BatchRouteUnit; +import io.shardingsphere.core.routing.RouteUnit; +import io.shardingsphere.core.routing.SQLRouteResult; +import lombok.Getter; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Prepared statement executor to process add batch. + * + * @author zhangliang + * @author maxiaoguang + * @author panjuan + */ +public final class BatchPreparedStatementExecutor extends AbstractStatementExecutor { + + private final Collection routeUnits = new LinkedList<>(); + + @Getter + private final boolean returnGeneratedKeys; + + private int batchCount; + + public BatchPreparedStatementExecutor(final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final boolean returnGeneratedKeys, + final ShardingConnection shardingConnection) { + super(resultSetType, resultSetConcurrency, resultSetHoldability, shardingConnection); + this.returnGeneratedKeys = returnGeneratedKeys; + } + + /** + * Initialize executor. + * + * @throws SQLException SQL exception + */ + public void init() throws SQLException { + getExecuteGroups().addAll(obtainExecuteGroups(routeUnits)); + } + + private Collection> obtainExecuteGroups(final Collection routeUnits) throws SQLException { + return getSqlExecutePrepareTemplate().getExecuteUnitGroups(Lists.transform(new ArrayList<>(routeUnits), new Function() { + + @Override + public RouteUnit apply(final BatchRouteUnit input) { + return input.getRouteUnit(); + } + }), new SQLExecutePrepareCallback() { + + @Override + public List getConnections(final String dataSourceName, final int connectionSize) throws SQLException { + return BatchPreparedStatementExecutor.super.getConnection().getConnections(dataSourceName, connectionSize); + } + + @Override + public StatementExecuteUnit createStatementExecuteUnit(final Connection connection, final RouteUnit routeUnit, final ConnectionMode connectionMode) throws SQLException { + PreparedStatement preparedStatement = createPreparedStatement(connection, routeUnit.getSqlUnit().getSql()); + return new StatementExecuteUnit(routeUnit, preparedStatement, connectionMode); + } + }); + } + + @SuppressWarnings("MagicConstant") + private PreparedStatement createPreparedStatement(final Connection connection, final String sql) throws SQLException { + return returnGeneratedKeys ? connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) + : connection.prepareStatement(sql, getResultSetType(), getResultSetConcurrency(), getResultSetHoldability()); + } + + /** + * Add batch for route units. + * + * @param routeResult route result + */ + public void addBatchForRouteUnits(final SQLRouteResult routeResult) { + setSqlType(routeResult.getSqlStatement().getType()); + handleOldRouteUnits(createBatchRouteUnits(routeResult.getRouteUnits())); + handleNewRouteUnits(createBatchRouteUnits(routeResult.getRouteUnits())); + batchCount++; + } + + private Collection createBatchRouteUnits(final Collection routeUnits) { + Collection result = new LinkedList<>(); + for (RouteUnit each : routeUnits) { + result.add(new BatchRouteUnit(each)); + } + return result; + } + + private void handleOldRouteUnits(final Collection newRouteUnits) { + for (final BatchRouteUnit each : newRouteUnits) { + Optional batchRouteUnitOptional = Iterators.tryFind(routeUnits.iterator(), new Predicate() { + @Override + public boolean apply(final BatchRouteUnit input) { + return input.equals(each); + } + }); + if (batchRouteUnitOptional.isPresent()) { + reviseBatchRouteUnit(batchRouteUnitOptional.get(), each); + } + } + } + + private void reviseBatchRouteUnit(final BatchRouteUnit oldBatchRouteUnit, final BatchRouteUnit newBatchRouteUnit) { + oldBatchRouteUnit.getRouteUnit().getSqlUnit().getParameterSets().add(newBatchRouteUnit.getRouteUnit().getSqlUnit().getParameterSets().get(0)); + oldBatchRouteUnit.mapAddBatchCount(batchCount); + } + + private void handleNewRouteUnits(final Collection newRouteUnits) { + newRouteUnits.removeAll(routeUnits); + for (BatchRouteUnit each : newRouteUnits) { + each.mapAddBatchCount(batchCount); + } + routeUnits.addAll(newRouteUnits); + } + + /** + * Execute batch. + * + * @return execute results + * @throws SQLException SQL exception + */ + public int[] executeBatch() throws SQLException { + final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); + final Map dataMap = ExecutorDataMap.getDataMap(); + SQLExecuteCallback callback = new SQLExecuteCallback(getDatabaseType(), getSqlType(), isExceptionThrown, dataMap) { + + @Override + protected int[] executeSQL(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + return statementExecuteUnit.getStatement().executeBatch(); + } + }; + return accumulate(executeCallback(callback)); + } + + private int[] accumulate(final List results) { + int[] result = new int[batchCount]; + int count = 0; + for (BatchRouteUnit each : routeUnits) { + for (Entry entry : each.getJdbcAndActualAddBatchCallTimesMap().entrySet()) { + int value = null == results.get(count) ? 0 : results.get(count)[entry.getValue()]; + if (DatabaseType.Oracle == getDatabaseType()) { + result[entry.getKey()] = value; + } else { + result[entry.getKey()] += value; + } + } + count++; + } + return result; + } + + /** + * Get statements. + * + * @return statements + */ + @Override + public List getStatements() { + List result = new LinkedList<>(); + for (ShardingExecuteGroup each : getExecuteGroups()) { + result.addAll(Lists.transform(each.getInputs(), new Function() { + + @Override + public Statement apply(final StatementExecuteUnit input) { + return input.getStatement(); + } + })); + } + return result; + } + + /** + * Get parameter sets. + * + * @param statement statement + * @return parameter sets + */ + public List> getParameterSet(final Statement statement) { + Optional target; + List> result = new LinkedList<>(); + for (ShardingExecuteGroup each : getExecuteGroups()) { + target = Iterators.tryFind(each.getInputs().iterator(), new Predicate() { + @Override + public boolean apply(final StatementExecuteUnit input) { + return input.getStatement().equals(statement); + } + }); + if (target.isPresent()) { + result.addAll(target.get().getRouteUnit().getSqlUnit().getParameterSets()); + break; + } + } + return result; + } + + @Override + public void clear() throws SQLException { + super.clear(); + batchCount = 0; + routeUnits.clear(); + } +} + + diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/PreparedStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/PreparedStatementExecutor.java new file mode 100644 index 0000000000000..f9e55ea62f36f --- /dev/null +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/PreparedStatementExecutor.java @@ -0,0 +1,172 @@ +/* + * Copyright 2016-2018 shardingsphere.io. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *

+ */ + +package io.shardingsphere.core.executor; + +import io.shardingsphere.core.constant.ConnectionMode; +import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; +import io.shardingsphere.core.executor.sql.execute.result.MemoryQueryResult; +import io.shardingsphere.core.executor.sql.execute.result.StreamQueryResult; +import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; +import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; +import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareCallback; +import io.shardingsphere.core.jdbc.core.connection.ShardingConnection; +import io.shardingsphere.core.merger.QueryResult; +import io.shardingsphere.core.routing.RouteUnit; +import io.shardingsphere.core.routing.SQLRouteResult; +import lombok.Getter; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Prepared statement executor. + * + * @author zhangliang + * @author caohao + * @author maxiaoguang + * @author panjuan + */ +public final class PreparedStatementExecutor extends AbstractStatementExecutor { + + @Getter + private final boolean returnGeneratedKeys; + + public PreparedStatementExecutor( + final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final boolean returnGeneratedKeys, final ShardingConnection shardingConnection) { + super(resultSetType, resultSetConcurrency, resultSetHoldability, shardingConnection); + this.returnGeneratedKeys = returnGeneratedKeys; + } + + /** + * Initialize executor. + * + * @param routeResult route result + * @throws SQLException SQL exception + */ + public void init(final SQLRouteResult routeResult) throws SQLException { + setSqlType(routeResult.getSqlStatement().getType()); + getExecuteGroups().addAll(obtainExecuteGroups(routeResult.getRouteUnits())); + } + + private Collection> obtainExecuteGroups(final Collection routeUnits) throws SQLException { + return getSqlExecutePrepareTemplate().getExecuteUnitGroups(routeUnits, new SQLExecutePrepareCallback() { + + @Override + public List getConnections(final String dataSourceName, final int connectionSize) throws SQLException { + return PreparedStatementExecutor.super.getConnection().getConnections(dataSourceName, connectionSize); + } + + @Override + public StatementExecuteUnit createStatementExecuteUnit(final Connection connection, final RouteUnit routeUnit, final ConnectionMode connectionMode) throws SQLException { + PreparedStatement preparedStatement = createPreparedStatement(connection, routeUnit.getSqlUnit().getSql()); + getStatements().add(preparedStatement); + getParameterSets().add(routeUnit.getSqlUnit().getParameterSets().get(0)); + return new StatementExecuteUnit(routeUnit, preparedStatement, connectionMode); + } + }); + } + + @SuppressWarnings("MagicConstant") + private PreparedStatement createPreparedStatement(final Connection connection, final String sql) throws SQLException { + return returnGeneratedKeys ? connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) + : connection.prepareStatement(sql, getResultSetType(), getResultSetConcurrency(), getResultSetHoldability()); + } + + /** + * Execute query. + * + * @return result set list + * @throws SQLException SQL exception + */ + public List executeQuery() throws SQLException { + final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); + final Map dataMap = ExecutorDataMap.getDataMap(); + SQLExecuteCallback executeCallback = new SQLExecuteCallback(getDatabaseType(), getSqlType(), isExceptionThrown, dataMap) { + + @Override + protected QueryResult executeSQL(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + return getQueryResult(statementExecuteUnit); + } + }; + return executeCallback(executeCallback); + } + + private QueryResult getQueryResult(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + PreparedStatement preparedStatement = (PreparedStatement) statementExecuteUnit.getStatement(); + ResultSet resultSet = preparedStatement.executeQuery(); + getResultSets().add(resultSet); + return ConnectionMode.MEMORY_STRICTLY == statementExecuteUnit.getConnectionMode() ? new StreamQueryResult(resultSet) : new MemoryQueryResult(resultSet); + } + + /** + * Execute update. + * + * @return effected records count + * @throws SQLException SQL exception + */ + public int executeUpdate() throws SQLException { + final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); + final Map dataMap = ExecutorDataMap.getDataMap(); + SQLExecuteCallback executeCallback = new SQLExecuteCallback(getDatabaseType(), getSqlType(), isExceptionThrown, dataMap) { + + @Override + protected Integer executeSQL(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + return ((PreparedStatement) statementExecuteUnit.getStatement()).executeUpdate(); + } + }; + List results = executeCallback(executeCallback); + return accumulate(results); + } + + private int accumulate(final List results) { + int result = 0; + for (Integer each : results) { + result += null == each ? 0 : each; + } + return result; + } + + /** + * Execute SQL. + * + * @return return true if is DQL, false if is DML + * @throws SQLException SQL exception + */ + public boolean execute() throws SQLException { + boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); + Map dataMap = ExecutorDataMap.getDataMap(); + SQLExecuteCallback executeCallback = new SQLExecuteCallback(getDatabaseType(), getSqlType(), isExceptionThrown, dataMap) { + + @Override + protected Boolean executeSQL(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + return ((PreparedStatement) statementExecuteUnit.getStatement()).execute(); + } + }; + List result = executeCallback(executeCallback); + if (null == result || result.isEmpty() || null == result.get(0)) { + return false; + } + return result.get(0); + } +} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/StatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/StatementExecutor.java similarity index 64% rename from sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/StatementExecutor.java rename to sharding-jdbc/src/main/java/io/shardingsphere/core/executor/StatementExecutor.java index bc2d6f65c6476..78c560299c004 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/StatementExecutor.java +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/StatementExecutor.java @@ -15,19 +15,25 @@ *

*/ -package io.shardingsphere.core.executor.statement; +package io.shardingsphere.core.executor; -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; +import io.shardingsphere.core.constant.ConnectionMode; import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; +import io.shardingsphere.core.executor.sql.execute.result.MemoryQueryResult; +import io.shardingsphere.core.executor.sql.execute.result.StreamQueryResult; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; -import lombok.RequiredArgsConstructor; +import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareCallback; +import io.shardingsphere.core.jdbc.core.connection.ShardingConnection; +import io.shardingsphere.core.merger.QueryResult; +import io.shardingsphere.core.routing.RouteUnit; +import io.shardingsphere.core.routing.SQLRouteResult; +import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -38,13 +44,43 @@ * @author caohao * @author zhangliang * @author maxiaoguang + * @author panjuan */ -@RequiredArgsConstructor -public abstract class StatementExecutor { +public final class StatementExecutor extends AbstractStatementExecutor { - private final DatabaseType databaseType; + public StatementExecutor(final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final ShardingConnection shardingConnection) { + super(resultSetType, resultSetConcurrency, resultSetHoldability, shardingConnection); + } + + /** + * Initialize executor. + * + * @param routeResult route result + * @throws SQLException SQL exception + */ + public void init(final SQLRouteResult routeResult) throws SQLException { + setSqlType(routeResult.getSqlStatement().getType()); + getExecuteGroups().addAll(obtainExecuteGroups(routeResult.getRouteUnits())); + } - private final SQLType sqlType; + private Collection> obtainExecuteGroups(final Collection routeUnits) throws SQLException { + return getSqlExecutePrepareTemplate().getExecuteUnitGroups(routeUnits, new SQLExecutePrepareCallback() { + + @Override + public List getConnections(final String dataSourceName, final int connectionSize) throws SQLException { + return StatementExecutor.super.getConnection().getConnections(dataSourceName, connectionSize); + } + + @SuppressWarnings("MagicConstant") + @Override + public StatementExecuteUnit createStatementExecuteUnit(final Connection connection, final RouteUnit routeUnit, final ConnectionMode connectionMode) throws SQLException { + Statement statement = connection.createStatement(getResultSetType(), getResultSetConcurrency(), getResultSetHoldability()); + getStatements().add(statement); + getParameterSets().add(routeUnit.getSqlUnit().getParameterSets().get(0)); + return new StatementExecuteUnit(routeUnit, statement, connectionMode); + } + }); + } /** * Execute query. @@ -52,19 +88,25 @@ public abstract class StatementExecutor { * @return result set list * @throws SQLException SQL exception */ - public List executeQuery() throws SQLException { + public List executeQuery() throws SQLException { final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); final Map dataMap = ExecutorDataMap.getDataMap(); - SQLExecuteCallback executeCallback = new SQLExecuteCallback(databaseType, sqlType, isExceptionThrown, dataMap) { + SQLExecuteCallback executeCallback = new SQLExecuteCallback(getDatabaseType(), getSqlType(), isExceptionThrown, dataMap) { @Override - protected ResultSet executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - return sqlExecuteUnit.getStatement().executeQuery(sqlExecuteUnit.getRouteUnit().getSqlUnit().getSql()); + protected QueryResult executeSQL(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + return getQueryResult(statementExecuteUnit); } }; return executeCallback(executeCallback); } + private QueryResult getQueryResult(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + ResultSet resultSet = statementExecuteUnit.getStatement().executeQuery(statementExecuteUnit.getRouteUnit().getSqlUnit().getSql()); + getResultSets().add(resultSet); + return ConnectionMode.MEMORY_STRICTLY == statementExecuteUnit.getConnectionMode() ? new StreamQueryResult(resultSet) : new MemoryQueryResult(resultSet); + } + /** * Execute update. * @@ -135,11 +177,11 @@ public int executeUpdate(final Statement statement, final String sql) throws SQL private int executeUpdate(final Updater updater) throws SQLException { final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); final Map dataMap = ExecutorDataMap.getDataMap(); - SQLExecuteCallback executeCallback = new SQLExecuteCallback(databaseType, sqlType, isExceptionThrown, dataMap) { + SQLExecuteCallback executeCallback = new SQLExecuteCallback(getDatabaseType(), getSqlType(), isExceptionThrown, dataMap) { @Override - protected Integer executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - return updater.executeUpdate(sqlExecuteUnit.getStatement(), sqlExecuteUnit.getRouteUnit().getSqlUnit().getSql()); + protected Integer executeSQL(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + return updater.executeUpdate(statementExecuteUnit.getStatement(), statementExecuteUnit.getRouteUnit().getSqlUnit().getSql()); } }; List results = executeCallback(executeCallback); @@ -224,11 +266,11 @@ public boolean execute(final Statement statement, final String sql) throws SQLEx private boolean execute(final Executor executor) throws SQLException { final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); final Map dataMap = ExecutorDataMap.getDataMap(); - SQLExecuteCallback executeCallback = new SQLExecuteCallback(databaseType, sqlType, isExceptionThrown, dataMap) { + SQLExecuteCallback executeCallback = new SQLExecuteCallback(getDatabaseType(), getSqlType(), isExceptionThrown, dataMap) { @Override - protected Boolean executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - return executor.execute(sqlExecuteUnit.getStatement(), sqlExecuteUnit.getRouteUnit().getSqlUnit().getSql()); + protected Boolean executeSQL(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + return executor.execute(statementExecuteUnit.getStatement(), statementExecuteUnit.getRouteUnit().getSqlUnit().getSql()); } }; List result = executeCallback(executeCallback); @@ -238,8 +280,6 @@ protected Boolean executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLExce return result.get(0); } - protected abstract List executeCallback(SQLExecuteCallback executeCallback) throws SQLException; - private interface Updater { int executeUpdate(Statement statement, String sql) throws SQLException; @@ -250,3 +290,4 @@ private interface Executor { boolean execute(Statement statement, String sql) throws SQLException; } } + diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/BatchPreparedStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/BatchPreparedStatementExecutor.java deleted file mode 100644 index fe41d1f45cd79..0000000000000 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/BatchPreparedStatementExecutor.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.executor.batch; - -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; -import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; -import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; -import lombok.RequiredArgsConstructor; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * Prepared statement executor to process add batch. - * - * @author zhangliang - * @author maxiaoguang - */ -@RequiredArgsConstructor -public abstract class BatchPreparedStatementExecutor { - - private final DatabaseType databaseType; - - private final SQLType sqlType; - - private final int batchCount; - - /** - * Execute batch. - * - * @return execute results - * @throws SQLException SQL exception - */ - public int[] executeBatch() throws SQLException { - final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); - final Map dataMap = ExecutorDataMap.getDataMap(); - SQLExecuteCallback callback = new SQLExecuteCallback(databaseType, sqlType, isExceptionThrown, dataMap) { - - @Override - protected int[] executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - return sqlExecuteUnit.getStatement().executeBatch(); - } - }; - return accumulate(executeCallback(callback)); - } - - private int[] accumulate(final List results) { - int[] result = new int[batchCount]; - int count = 0; - for (BatchPreparedStatementExecuteUnit each : getBatchPreparedStatementUnitGroups()) { - for (Entry entry : each.getJdbcAndActualAddBatchCallTimesMap().entrySet()) { - int value = null == results.get(count) ? 0 : results.get(count)[entry.getValue()]; - if (DatabaseType.Oracle == databaseType) { - result[entry.getKey()] = value; - } else { - result[entry.getKey()] += value; - } - } - count++; - } - return result; - } - - protected abstract List executeCallback(SQLExecuteCallback executeCallback) throws SQLException; - - protected abstract Collection getBatchPreparedStatementUnitGroups(); -} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/ConnectionStrictlyBatchPreparedStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/ConnectionStrictlyBatchPreparedStatementExecutor.java deleted file mode 100644 index a0955f49e2bb8..0000000000000 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/ConnectionStrictlyBatchPreparedStatementExecutor.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.executor.batch; - -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; - -/** - * Prepared statement executor to process add batch for connection strictly mode. - * - * @author zhangliang - */ -public final class ConnectionStrictlyBatchPreparedStatementExecutor extends BatchPreparedStatementExecutor { - - private final SQLExecuteTemplate executeTemplate; - - private final List> batchPreparedStatementUnitGroups; - - public ConnectionStrictlyBatchPreparedStatementExecutor(final DatabaseType dbType, final SQLType sqlType, final int batchCount, - final SQLExecuteTemplate executeTemplate, final List> batchPreparedStatementUnitGroups) { - super(dbType, sqlType, batchCount); - this.executeTemplate = executeTemplate; - this.batchPreparedStatementUnitGroups = batchPreparedStatementUnitGroups; - } - - @SuppressWarnings("unchecked") - @Override - protected List executeCallback(final SQLExecuteCallback executeCallback) throws SQLException { - return executeTemplate.executeGroup((Collection) batchPreparedStatementUnitGroups, executeCallback); - } - - @Override - protected Collection getBatchPreparedStatementUnitGroups() { - Collection result = new LinkedList<>(); - for (List each : batchPreparedStatementUnitGroups) { - result.addAll(each); - } - return result; - } -} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/MemoryStrictlyBatchPreparedStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/MemoryStrictlyBatchPreparedStatementExecutor.java deleted file mode 100644 index c88b274118f54..0000000000000 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/batch/MemoryStrictlyBatchPreparedStatementExecutor.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.executor.batch; - -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.List; - -/** - * Prepared statement executor to process add batch for memory strictly mode. - * - * @author zhangliang - */ -public final class MemoryStrictlyBatchPreparedStatementExecutor extends BatchPreparedStatementExecutor { - - private final SQLExecuteTemplate executeTemplate; - - private final Collection batchPreparedStatementUnits; - - public MemoryStrictlyBatchPreparedStatementExecutor(final DatabaseType dbType, final SQLType sqlType, final int batchCount, - final SQLExecuteTemplate executeTemplate, final Collection batchPreparedStatementUnits) { - super(dbType, sqlType, batchCount); - this.executeTemplate = executeTemplate; - this.batchPreparedStatementUnits = batchPreparedStatementUnits; - } - - @Override - protected List executeCallback(final SQLExecuteCallback executeCallback) throws SQLException { - return executeTemplate.execute(batchPreparedStatementUnits, executeCallback); - } - - @Override - protected Collection getBatchPreparedStatementUnitGroups() { - return batchPreparedStatementUnits; - } -} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/ConnectionStrictlyPreparedStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/ConnectionStrictlyPreparedStatementExecutor.java deleted file mode 100644 index 8a825f75e064c..0000000000000 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/ConnectionStrictlyPreparedStatementExecutor.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.executor.prepared; - -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.ShardingExecuteGroup; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.List; - -/** - * Prepared statement executor for connection strictly mode. - * - * @author zhangliang - */ -public final class ConnectionStrictlyPreparedStatementExecutor extends PreparedStatementExecutor { - - private final SQLExecuteTemplate executeTemplate; - - private final Collection> executeGroups; - - public ConnectionStrictlyPreparedStatementExecutor( - final DatabaseType databaseType, final SQLType sqlType, final SQLExecuteTemplate executeTemplate, final Collection> executeGroups) { - super(databaseType, sqlType); - this.executeTemplate = executeTemplate; - this.executeGroups = executeGroups; - } - - @SuppressWarnings("unchecked") - @Override - protected List executeCallback(final SQLExecuteCallback executeCallback) throws SQLException { - return executeTemplate.executeGroup((Collection) executeGroups, executeCallback); - } -} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/MemoryStrictlyPreparedStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/MemoryStrictlyPreparedStatementExecutor.java deleted file mode 100644 index edf6029975fc5..0000000000000 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/MemoryStrictlyPreparedStatementExecutor.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.executor.prepared; - -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.List; - -/** - * Prepared statement executor for memory strictly mode. - * - * @author zhangliang - */ -public final class MemoryStrictlyPreparedStatementExecutor extends PreparedStatementExecutor { - - private final SQLExecuteTemplate executeTemplate; - - private final Collection preparedStatementExecuteUnits; - - public MemoryStrictlyPreparedStatementExecutor( - final DatabaseType databaseType, final SQLType sqlType, final SQLExecuteTemplate executeTemplate, final Collection preparedStatementExecuteUnits) { - super(databaseType, sqlType); - this.executeTemplate = executeTemplate; - this.preparedStatementExecuteUnits = preparedStatementExecuteUnits; - } - - @Override - protected List executeCallback(final SQLExecuteCallback executeCallback) throws SQLException { - return executeTemplate.execute(preparedStatementExecuteUnits, executeCallback); - } -} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/PreparedStatementExecuteUnit.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/PreparedStatementExecuteUnit.java deleted file mode 100644 index aec1be1445b4e..0000000000000 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/PreparedStatementExecuteUnit.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.executor.prepared; - -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; -import io.shardingsphere.core.routing.RouteUnit; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.sql.PreparedStatement; - -/** - * Execute unit for JDBC prepared statement. - * - * @author zhangliang - */ -@RequiredArgsConstructor -@Getter -public final class PreparedStatementExecuteUnit implements SQLExecuteUnit { - - private final RouteUnit routeUnit; - - private final PreparedStatement statement; -} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/PreparedStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/PreparedStatementExecutor.java deleted file mode 100644 index a1ff80edc6264..0000000000000 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/prepared/PreparedStatementExecutor.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.executor.prepared; - -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; -import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; -import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; -import lombok.RequiredArgsConstructor; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; - -/** - * Prepared statement executor. - * - * @author zhangliang - * @author caohao - * @author maxiaoguang - */ -@RequiredArgsConstructor -public abstract class PreparedStatementExecutor { - - private final DatabaseType databaseType; - - private final SQLType sqlType; - - /** - * Execute query. - * - * @return result set list - * @throws SQLException SQL exception - */ - public List executeQuery() throws SQLException { - final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); - final Map dataMap = ExecutorDataMap.getDataMap(); - SQLExecuteCallback executeCallback = new SQLExecuteCallback(databaseType, sqlType, isExceptionThrown, dataMap) { - - @Override - protected ResultSet executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - return ((PreparedStatement) sqlExecuteUnit.getStatement()).executeQuery(); - } - }; - return executeCallback(executeCallback); - } - - /** - * Execute update. - * - * @return effected records count - * @throws SQLException SQL exception - */ - public int executeUpdate() throws SQLException { - final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); - final Map dataMap = ExecutorDataMap.getDataMap(); - SQLExecuteCallback executeCallback = new SQLExecuteCallback(databaseType, sqlType, isExceptionThrown, dataMap) { - - @Override - protected Integer executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - return ((PreparedStatement) sqlExecuteUnit.getStatement()).executeUpdate(); - } - }; - List results = executeCallback(executeCallback); - return accumulate(results); - } - - private int accumulate(final List results) { - int result = 0; - for (Integer each : results) { - result += null == each ? 0 : each; - } - return result; - } - - /** - * Execute SQL. - * - * @return return true if is DQL, false if is DML - * @throws SQLException SQL exception - */ - public boolean execute() throws SQLException { - boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); - Map dataMap = ExecutorDataMap.getDataMap(); - SQLExecuteCallback executeCallback = new SQLExecuteCallback(databaseType, sqlType, isExceptionThrown, dataMap) { - - @Override - protected Boolean executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - return ((PreparedStatement) sqlExecuteUnit.getStatement()).execute(); - } - }; - List result = executeCallback(executeCallback); - if (null == result || result.isEmpty() || null == result.get(0)) { - return false; - } - return result.get(0); - } - - protected abstract List executeCallback(SQLExecuteCallback executeCallback) throws SQLException; -} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/ConnectionStrictlyStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/ConnectionStrictlyStatementExecutor.java deleted file mode 100644 index cbfef654e8fe4..0000000000000 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/ConnectionStrictlyStatementExecutor.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.executor.statement; - -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.ShardingExecuteGroup; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.List; - -/** - * Statement executor for connection strictly mode. - * - * @author zhangliang - */ -public final class ConnectionStrictlyStatementExecutor extends StatementExecutor { - - private final SQLExecuteTemplate executeTemplate; - - private final Collection> executeGroups; - - public ConnectionStrictlyStatementExecutor( - final DatabaseType databaseType, final SQLType sqlType, final SQLExecuteTemplate executeTemplate, final Collection> executeGroups) { - super(databaseType, sqlType); - this.executeTemplate = executeTemplate; - this.executeGroups = executeGroups; - } - - @SuppressWarnings("unchecked") - @Override - protected List executeCallback(final SQLExecuteCallback executeCallback) throws SQLException { - return executeTemplate.executeGroup((Collection) executeGroups, executeCallback); - } -} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/MemoryStrictlyStatementExecutor.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/MemoryStrictlyStatementExecutor.java deleted file mode 100644 index a5412f3856fd3..0000000000000 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/executor/statement/MemoryStrictlyStatementExecutor.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.core.executor.statement; - -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.List; - -/** - * Statement executor for memory strictly mode. - * - * @author zhangliang - */ -public final class MemoryStrictlyStatementExecutor extends StatementExecutor { - - private final SQLExecuteTemplate executeTemplate; - - private final Collection statementExecuteUnits; - - public MemoryStrictlyStatementExecutor( - final DatabaseType databaseType, final SQLType sqlType, final SQLExecuteTemplate executeTemplate, final Collection statementExecuteUnits) { - super(databaseType, sqlType); - this.executeTemplate = executeTemplate; - this.statementExecuteUnits = statementExecuteUnits; - } - - @Override - protected List executeCallback(final SQLExecuteCallback executeCallback) throws SQLException { - return executeTemplate.execute(statementExecuteUnits, executeCallback); - } -} diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/adapter/AbstractConnectionAdapter.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/adapter/AbstractConnectionAdapter.java index c716a865526ff..c7a41a1f0dce2 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/adapter/AbstractConnectionAdapter.java +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/adapter/AbstractConnectionAdapter.java @@ -18,6 +18,8 @@ package io.shardingsphere.core.jdbc.adapter; import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import io.shardingsphere.core.constant.DatabaseType; import io.shardingsphere.core.constant.transaction.TransactionOperationType; import io.shardingsphere.core.constant.transaction.TransactionType; @@ -29,7 +31,6 @@ import io.shardingsphere.core.event.connection.GetConnectionFinishEvent; import io.shardingsphere.core.event.connection.GetConnectionStartEvent; import io.shardingsphere.core.event.root.RootInvokeEvent; -import io.shardingsphere.core.event.root.RootInvokeFinishEvent; import io.shardingsphere.core.event.transaction.xa.XATransactionEvent; import io.shardingsphere.core.hint.HintManagerHolder; import io.shardingsphere.core.jdbc.adapter.executor.ForceExecuteCallback; @@ -45,20 +46,23 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.Map; /** * Adapter for {@code Connection}. * * @author zhangliang + * @author panjuan */ @RequiredArgsConstructor public abstract class AbstractConnectionAdapter extends AbstractUnsupportedOperationConnection { private final DatabaseType databaseType; - private final Map cachedConnections = new HashMap<>(); + private final Multimap cachedConnections = HashMultimap.create(); private boolean autoCommit = true; @@ -80,31 +84,56 @@ public abstract class AbstractConnectionAdapter extends AbstractUnsupportedOpera * @throws SQLException SQL exception */ public final Connection getConnection(final String dataSourceName) throws SQLException { + return getConnections(dataSourceName, 1).get(0); + } + + /** + * Get database connections. + * + * @param dataSourceName data source name + * @param connectionSize size of connection list to be get + * @return database connections + * @throws SQLException SQL exception + */ + public final List getConnections(final String dataSourceName, final int connectionSize) throws SQLException { ShardingEventBusInstance.getInstance().post(new GetConnectionStartEvent(dataSourceName)); - try { - if (cachedConnections.containsKey(dataSourceName)) { - GetConnectionEvent finishEvent = new GetConnectionFinishEvent(DataSourceMetaDataFactory.newInstance(databaseType, cachedConnections.get(dataSourceName).getMetaData().getURL())); - finishEvent.setExecuteSuccess(); - ShardingEventBusInstance.getInstance().post(finishEvent); - return cachedConnections.get(dataSourceName); + DataSource dataSource = getDataSourceMap().get(dataSourceName); + Preconditions.checkState(null != dataSource, "Missing the data source name: '%s'", dataSourceName); + Collection connections = cachedConnections.get(dataSourceName); + List result; + if (connections.size() >= connectionSize) { + result = new ArrayList<>(cachedConnections.get(dataSourceName)).subList(0, connectionSize); + } else if (!connections.isEmpty()) { + result = new ArrayList<>(connectionSize); + result.addAll(connections); + List newConnections = createConnections(dataSource, connectionSize - connections.size()); + result.addAll(newConnections); + cachedConnections.putAll(dataSourceName, newConnections); + } else { + result = new ArrayList<>(createConnections(dataSource, connectionSize)); + cachedConnections.putAll(dataSourceName, result); + } + postGetConnectionEvent(result); + return result; + } + + @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") + private synchronized List createConnections(final DataSource dataSource, final int connectionSize) throws SQLException { + List result = new ArrayList<>(connectionSize); + synchronized (dataSource) { + for (int i = 0; i < connectionSize; i++) { + Connection connection = dataSource.getConnection(); + replayMethodsInvocation(connection); + result.add(connection); } - DataSource dataSource = getDataSourceMap().get(dataSourceName); - Preconditions.checkState(null != dataSource, "Missing the data source name: '%s'", dataSourceName); - Connection result = dataSource.getConnection(); - cachedConnections.put(dataSourceName, result); - replayMethodsInvocation(result); - GetConnectionEvent finishEvent = new GetConnectionFinishEvent(DataSourceMetaDataFactory.newInstance(databaseType, cachedConnections.get(dataSourceName).getMetaData().getURL())); - finishEvent.setExecuteSuccess(); - ShardingEventBusInstance.getInstance().post(finishEvent); - return result; - // CHECKSTYLE:OFF - } catch (final Exception ex) { - // CHECKSTYLE:ON - GetConnectionEvent finishEvent = new GetConnectionFinishEvent(null); - finishEvent.setExecuteFailure(ex); - ShardingEventBusInstance.getInstance().post(finishEvent); - throw ex; } + return result; + } + + private void postGetConnectionEvent(final List connections) throws SQLException { + GetConnectionEvent finishEvent = new GetConnectionFinishEvent(DataSourceMetaDataFactory.newInstance(databaseType, connections.get(0).getMetaData().getURL())); + finishEvent.setExecuteSuccess(); + ShardingEventBusInstance.getInstance().post(finishEvent); } protected abstract Map getDataSourceMap(); @@ -174,7 +203,7 @@ public final void close() throws SQLException { HintManagerHolder.clear(); MasterVisitedManager.clear(); TransactionTypeHolder.clear(); - forceExecuteTemplateForClose.execute(cachedConnections.entrySet(), new ForceExecuteCallback>() { + forceExecuteTemplateForClose.execute(cachedConnections.entries(), new ForceExecuteCallback>() { @Override public void execute(final Map.Entry cachedConnectionsEntrySet) throws SQLException { @@ -195,11 +224,11 @@ public void execute(final Map.Entry cachedConnectionsEntrySe } } }); - RootInvokeEvent finishEvent = new RootInvokeFinishEvent(); + RootInvokeEvent finishEvent = new RootInvokeEvent(); finishEvent.setExecuteSuccess(); ShardingEventBusInstance.getInstance().post(finishEvent); } - + @Override public final boolean isClosed() { return closed; diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/adapter/AbstractDataSourceAdapter.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/adapter/AbstractDataSourceAdapter.java index b1774f045bf15..fd2ae92eeca18 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/adapter/AbstractDataSourceAdapter.java +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/adapter/AbstractDataSourceAdapter.java @@ -22,6 +22,8 @@ import io.shardingsphere.core.event.ShardingEventListenerRegistrySPILoader; import io.shardingsphere.core.jdbc.unsupported.AbstractUnsupportedOperationDataSource; import lombok.Getter; +import lombok.Setter; + import javax.sql.DataSource; import java.io.PrintWriter; import java.sql.Connection; @@ -35,14 +37,15 @@ * @author zhangliang * @author panjuan */ +@Getter +@Setter public abstract class AbstractDataSourceAdapter extends AbstractUnsupportedOperationDataSource { static { ShardingEventListenerRegistrySPILoader.registerListeners(); } - @Getter - private DatabaseType databaseType; + private final DatabaseType databaseType; private PrintWriter logWriter = new PrintWriter(System.out); @@ -73,16 +76,6 @@ private DatabaseType getDatabaseType(final DataSource dataSource) throws SQLExce } } - @Override - public final PrintWriter getLogWriter() { - return logWriter; - } - - @Override - public final void setLogWriter(final PrintWriter out) { - this.logWriter = out; - } - @Override public final Logger getParentLogger() { return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/ShardingContext.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/ShardingContext.java index 339e37c7b97cf..5db5a4374bfe4 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/ShardingContext.java +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/ShardingContext.java @@ -17,9 +17,7 @@ package io.shardingsphere.core.jdbc.core; -import io.shardingsphere.core.constant.ConnectionMode; import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.exception.ShardingException; import io.shardingsphere.core.executor.ShardingExecuteEngine; import io.shardingsphere.core.jdbc.metadata.JDBCTableMetaDataConnectionManager; import io.shardingsphere.core.metadata.ShardingMetaData; @@ -42,37 +40,30 @@ @Getter public final class ShardingContext implements AutoCloseable { - private ShardingRule shardingRule; + private final ShardingRule shardingRule; - private DatabaseType databaseType; + private final DatabaseType databaseType; - private ShardingExecuteEngine executeEngine; + private final ShardingExecuteEngine executeEngine; - private ShardingMetaData metaData; + private final int maxConnectionsSizePerQuery; - private ConnectionMode connectionMode; + private final boolean showSQL; - private int maxConnectionsSizePerQuery; + private final ShardingMetaData metaData; - private boolean showSQL; - - public ShardingContext(final Map dataSourceMap, final ShardingRule shardingRule, final DatabaseType databaseType, - final ShardingExecuteEngine executeEngine, final ConnectionMode connectionMode, final int maxConnectionsSizePerQuery, final boolean showSQL) { - init(dataSourceMap, shardingRule, databaseType, executeEngine, connectionMode, maxConnectionsSizePerQuery, showSQL); - } - - private void init(final Map dataSourceMap, final ShardingRule shardingRule, final DatabaseType databaseType, - final ShardingExecuteEngine executeEngine, final ConnectionMode connectionMode, final int maxConnectionsSizePerQuery, final boolean showSQL) { + public ShardingContext(final Map dataSourceMap, final ShardingRule shardingRule, + final DatabaseType databaseType, final ShardingExecuteEngine executeEngine, final int maxConnectionsSizePerQuery, final boolean showSQL) throws SQLException { this.shardingRule = shardingRule; - this.executeEngine = executeEngine; this.databaseType = databaseType; - this.connectionMode = connectionMode; + this.executeEngine = executeEngine; this.maxConnectionsSizePerQuery = maxConnectionsSizePerQuery; this.showSQL = showSQL; - metaData = new ShardingMetaData(getDataSourceURLs(dataSourceMap), shardingRule, databaseType, executeEngine, new JDBCTableMetaDataConnectionManager(dataSourceMap), maxConnectionsSizePerQuery); + metaData = new ShardingMetaData( + getDataSourceURLs(dataSourceMap), shardingRule, databaseType, executeEngine, new JDBCTableMetaDataConnectionManager(dataSourceMap), maxConnectionsSizePerQuery); } - private static Map getDataSourceURLs(final Map dataSourceMap) { + private Map getDataSourceURLs(final Map dataSourceMap) throws SQLException { Map result = new LinkedHashMap<>(dataSourceMap.size(), 1); for (Entry entry : dataSourceMap.entrySet()) { result.put(entry.getKey(), getDataSourceURL(entry.getValue())); @@ -80,11 +71,9 @@ private static Map getDataSourceURLs(final Map dataSourceMap; - public ShardingConnection(final ShardingDataSource shardingDataSource) { - super(shardingDataSource.getDatabaseType()); - this.shardingDataSource = shardingDataSource; - ShardingEventBusInstance.getInstance().post(new RootInvokeStartEvent(true)); + private final ShardingContext shardingContext; + + public ShardingConnection(final Map dataSourceMap, final ShardingContext shardingContext) { + super(shardingContext.getDatabaseType()); + this.dataSourceMap = dataSourceMap; + this.shardingContext = shardingContext; + ShardingEventBusInstance.getInstance().post(new RootInvokeEvent()); } /** @@ -66,16 +69,11 @@ public void release(final Connection connection) { } } - @Override - protected Map getDataSourceMap() { - return shardingDataSource.getDataSourceMap(); - } - @Override public DatabaseMetaData getMetaData() throws SQLException { - Collection masterSlaveRules = shardingDataSource.getShardingContext().getShardingRule().getMasterSlaveRules(); + Collection masterSlaveRules = shardingContext.getShardingRule().getMasterSlaveRules(); if (masterSlaveRules.isEmpty()) { - return getConnection(shardingDataSource.getDataSourceMap().keySet().iterator().next()).getMetaData(); + return getConnection(dataSourceMap.keySet().iterator().next()).getMetaData(); } for (MasterSlaveRule each : masterSlaveRules) { if (getDataSourceMap().containsKey(each.getMasterDataSourceName())) { diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/datasource/ShardingDataSource.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/datasource/ShardingDataSource.java index 64741341de750..bcf7fcdbc2dbf 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/datasource/ShardingDataSource.java +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/datasource/ShardingDataSource.java @@ -19,8 +19,6 @@ import com.google.common.base.Preconditions; import io.shardingsphere.core.api.ConfigMapContext; -import io.shardingsphere.core.constant.ConnectionMode; -import io.shardingsphere.core.constant.DatabaseType; import io.shardingsphere.core.constant.properties.ShardingProperties; import io.shardingsphere.core.constant.properties.ShardingPropertiesConstant; import io.shardingsphere.core.executor.ShardingExecuteEngine; @@ -64,11 +62,11 @@ public ShardingDataSource(final Map dataSourceMap, final Sha } this.dataSourceMap = dataSourceMap; this.shardingProperties = new ShardingProperties(null == props ? new Properties() : props); - this.shardingContext = getShardingContext(dataSourceMap, shardingRule); + this.shardingContext = getShardingContext(shardingRule); } - public ShardingDataSource(final Map dataSourceMap, final ShardingContext shardingContext, final ShardingProperties shardingProperties, final DatabaseType databaseType) { - super(databaseType); + public ShardingDataSource(final Map dataSourceMap, final ShardingContext shardingContext, final ShardingProperties shardingProperties) { + super(shardingContext.getDatabaseType()); this.dataSourceMap = dataSourceMap; this.shardingContext = shardingContext; this.shardingProperties = shardingProperties; @@ -80,18 +78,16 @@ private void checkDataSourceType(final Map dataSourceMap) { } } - private ShardingContext getShardingContext(final Map dataSourceMap, final ShardingRule shardingRule) { - boolean showSQL = shardingProperties.getValue(ShardingPropertiesConstant.SQL_SHOW); + private ShardingContext getShardingContext(final ShardingRule shardingRule) throws SQLException { int executorSize = shardingProperties.getValue(ShardingPropertiesConstant.EXECUTOR_SIZE); - ShardingExecuteEngine executeEngine = new ShardingExecuteEngine(executorSize); - ConnectionMode connectionMode = ConnectionMode.valueOf(shardingProperties.getValue(ShardingPropertiesConstant.CONNECTION_MODE)); int maxConnectionsSizePerQuery = shardingProperties.getValue(ShardingPropertiesConstant.MAX_CONNECTIONS_SIZE_PER_QUERY); - return new ShardingContext(dataSourceMap, shardingRule, getDatabaseType(), executeEngine, connectionMode, maxConnectionsSizePerQuery, showSQL); + boolean showSQL = shardingProperties.getValue(ShardingPropertiesConstant.SQL_SHOW); + return new ShardingContext(dataSourceMap, shardingRule, getDatabaseType(), new ShardingExecuteEngine(executorSize), maxConnectionsSizePerQuery, showSQL); } @Override public final ShardingConnection getConnection() { - return new ShardingConnection(this); + return new ShardingConnection(dataSourceMap, shardingContext); } @Override diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/MasterSlavePreparedStatement.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/MasterSlavePreparedStatement.java index b5d706eb0fc00..717e3c43f4c22 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/MasterSlavePreparedStatement.java +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/MasterSlavePreparedStatement.java @@ -21,6 +21,7 @@ import io.shardingsphere.core.jdbc.adapter.AbstractMasterSlavePreparedStatementAdapter; import io.shardingsphere.core.jdbc.core.connection.MasterSlaveConnection; import io.shardingsphere.core.routing.router.masterslave.MasterSlaveRouter; +import lombok.AccessLevel; import lombok.Getter; import java.sql.PreparedStatement; @@ -40,6 +41,7 @@ public final class MasterSlavePreparedStatement extends AbstractMasterSlavePrepa private final MasterSlaveConnection connection; + @Getter(AccessLevel.NONE) private final MasterSlaveRouter masterSlaveRouter; private final Collection routedStatements = new LinkedList<>(); diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/MasterSlaveStatement.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/MasterSlaveStatement.java index 40e04347960c1..565b05ba190f0 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/MasterSlaveStatement.java +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/MasterSlaveStatement.java @@ -21,6 +21,7 @@ import io.shardingsphere.core.jdbc.adapter.AbstractStatementAdapter; import io.shardingsphere.core.jdbc.core.connection.MasterSlaveConnection; import io.shardingsphere.core.routing.router.masterslave.MasterSlaveRouter; +import lombok.AccessLevel; import lombok.Getter; import java.sql.ResultSet; @@ -40,6 +41,7 @@ public final class MasterSlaveStatement extends AbstractStatementAdapter { private final MasterSlaveConnection connection; + @Getter(AccessLevel.NONE) private final MasterSlaveRouter masterSlaveRouter; private final int resultSetType; diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/ShardingPreparedStatement.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/ShardingPreparedStatement.java index fe41ca4c54cfc..1861180129132 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/ShardingPreparedStatement.java +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/ShardingPreparedStatement.java @@ -17,27 +17,13 @@ package io.shardingsphere.core.jdbc.core.statement; +import com.google.common.base.Function; import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterators; -import com.google.common.collect.Lists; -import io.shardingsphere.core.constant.ConnectionMode; -import io.shardingsphere.core.constant.DatabaseType; +import com.google.common.collect.Collections2; import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.ShardingExecuteGroup; -import io.shardingsphere.core.executor.batch.BatchPreparedStatementExecuteUnit; -import io.shardingsphere.core.executor.batch.ConnectionStrictlyBatchPreparedStatementExecutor; -import io.shardingsphere.core.executor.batch.MemoryStrictlyBatchPreparedStatementExecutor; -import io.shardingsphere.core.executor.prepared.ConnectionStrictlyPreparedStatementExecutor; -import io.shardingsphere.core.executor.prepared.MemoryStrictlyPreparedStatementExecutor; -import io.shardingsphere.core.executor.prepared.PreparedStatementExecuteUnit; -import io.shardingsphere.core.executor.prepared.PreparedStatementExecutor; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; -import io.shardingsphere.core.executor.sql.execute.result.MemoryQueryResult; +import io.shardingsphere.core.executor.BatchPreparedStatementExecutor; +import io.shardingsphere.core.executor.PreparedStatementExecutor; import io.shardingsphere.core.executor.sql.execute.result.StreamQueryResult; -import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareCallback; -import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareTemplate; import io.shardingsphere.core.jdbc.adapter.AbstractShardingPreparedStatementAdapter; import io.shardingsphere.core.jdbc.core.ShardingContext; import io.shardingsphere.core.jdbc.core.connection.ShardingConnection; @@ -53,24 +39,17 @@ import io.shardingsphere.core.parsing.parser.sql.dql.DQLStatement; import io.shardingsphere.core.parsing.parser.sql.dql.select.SelectStatement; import io.shardingsphere.core.routing.PreparedStatementRoutingEngine; -import io.shardingsphere.core.routing.RouteUnit; import io.shardingsphere.core.routing.SQLRouteResult; import io.shardingsphere.core.routing.router.sharding.GeneratedKey; -import lombok.AccessLevel; import lombok.Getter; -import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.Objects; /** * PreparedStatement that support sharding. @@ -80,73 +59,57 @@ * @author maxiaoguang * @author panjuan */ -@Getter public final class ShardingPreparedStatement extends AbstractShardingPreparedStatementAdapter { + @Getter private final ShardingConnection connection; - private final int resultSetType; - - private final int resultSetConcurrency; - - private final int resultSetHoldability; - private final PreparedStatementRoutingEngine routingEngine; - private final List batchStatementUnits = new LinkedList<>(); - - private final Collection routedStatements = new LinkedList<>(); + private final PreparedStatementExecutor preparedStatementExecutor; - private final String sql; + private final BatchPreparedStatementExecutor batchPreparedStatementExecutor; - private int batchCount; - - @Getter(AccessLevel.NONE) - private boolean returnGeneratedKeys; - - @Getter(AccessLevel.NONE) private SQLRouteResult routeResult; - @Getter(AccessLevel.NONE) private ResultSet currentResultSet; public ShardingPreparedStatement(final ShardingConnection connection, final String sql) { - this(connection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT); + this(connection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT, false); } public ShardingPreparedStatement(final ShardingConnection connection, final String sql, final int resultSetType, final int resultSetConcurrency) { - this(connection, sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT); + this(connection, sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT, false); } public ShardingPreparedStatement(final ShardingConnection connection, final String sql, final int autoGeneratedKeys) { - this(connection, sql); - if (Statement.RETURN_GENERATED_KEYS == autoGeneratedKeys) { - returnGeneratedKeys = true; - } + this(connection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT, Statement.RETURN_GENERATED_KEYS == autoGeneratedKeys); } public ShardingPreparedStatement(final ShardingConnection connection, final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { + this(connection, sql, resultSetType, resultSetConcurrency, resultSetHoldability, false); + } + + private ShardingPreparedStatement( + final ShardingConnection connection, final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final boolean returnGeneratedKeys) { this.connection = connection; - this.resultSetType = resultSetType; - this.resultSetConcurrency = resultSetConcurrency; - this.resultSetHoldability = resultSetHoldability; - this.sql = sql; - ShardingContext shardingContext = connection.getShardingDataSource().getShardingContext(); - routingEngine = new PreparedStatementRoutingEngine(sql, shardingContext.getShardingRule(), - shardingContext.getMetaData().getTable(), shardingContext.getDatabaseType(), shardingContext.isShowSQL(), shardingContext.getMetaData().getDataSource()); + ShardingContext shardingContext = connection.getShardingContext(); + routingEngine = new PreparedStatementRoutingEngine(sql, shardingContext.getShardingRule(), + shardingContext.getMetaData().getTable(), shardingContext.getDatabaseType(), shardingContext.isShowSQL(), shardingContext.getMetaData().getDataSource()); + preparedStatementExecutor = new PreparedStatementExecutor(resultSetType, resultSetConcurrency, resultSetHoldability, returnGeneratedKeys, connection); + batchPreparedStatementExecutor = new BatchPreparedStatementExecutor(resultSetType, resultSetConcurrency, resultSetHoldability, returnGeneratedKeys, connection); } @Override public ResultSet executeQuery() throws SQLException { - routedStatements.clear(); ResultSet result; try { + clearPrevious(); sqlRoute(); - List resultSets = getPreparedStatementExecutor().executeQuery(); - MergeEngine mergeEngine = MergeEngineFactory.newInstance( - connection.getShardingDataSource().getShardingContext().getShardingRule(), getQueryResults(resultSets), routeResult.getSqlStatement(), - connection.getShardingDataSource().getShardingContext().getMetaData().getTable()); - result = new ShardingResultSet(resultSets, mergeEngine.merge(), this); + initPreparedStatementExecutor(); + MergeEngine mergeEngine = MergeEngineFactory.newInstance(connection.getShardingContext().getShardingRule(), + preparedStatementExecutor.executeQuery(), routeResult.getSqlStatement(), connection.getShardingContext().getMetaData().getTable()); + result = new ShardingResultSet(preparedStatementExecutor.getResultSets(), mergeEngine.merge(), this); } finally { clearBatch(); } @@ -154,24 +117,13 @@ public ResultSet executeQuery() throws SQLException { return result; } - private List getQueryResults(final List resultSets) throws SQLException { - List result = new ArrayList<>(resultSets.size()); - for (ResultSet each : resultSets) { - if (ConnectionMode.MEMORY_STRICTLY == connection.getShardingDataSource().getShardingContext().getConnectionMode()) { - result.add(new StreamQueryResult(each)); - } else { - result.add(new MemoryQueryResult(each)); - } - } - return result; - } - @Override public int executeUpdate() throws SQLException { - routedStatements.clear(); try { + clearPrevious(); sqlRoute(); - return getPreparedStatementExecutor().executeUpdate(); + initPreparedStatementExecutor(); + return preparedStatementExecutor.executeUpdate(); } finally { refreshTableMetaData(); clearBatch(); @@ -180,205 +132,164 @@ public int executeUpdate() throws SQLException { @Override public boolean execute() throws SQLException { - routedStatements.clear(); try { + clearPrevious(); sqlRoute(); - return getPreparedStatementExecutor().execute(); + initPreparedStatementExecutor(); + return preparedStatementExecutor.execute(); } finally { refreshTableMetaData(); clearBatch(); } } - // TODO refresh table meta data by SQL parse result - private void refreshTableMetaData() throws SQLException { - if (null != routeResult && null != connection && SQLType.DDL == routeResult.getSqlStatement().getType() && !routeResult.getSqlStatement().getTables().isEmpty()) { - String logicTableName = routeResult.getSqlStatement().getTables().getSingleTableName(); - TableMetaDataLoader tableMetaDataLoader = new TableMetaDataLoader(connection.getShardingDataSource().getShardingContext().getMetaData().getDataSource(), - connection.getShardingDataSource().getShardingContext().getExecuteEngine(), new JDBCTableMetaDataConnectionManager(connection.getShardingDataSource().getDataSourceMap()), - connection.getShardingDataSource().getShardingContext().getMaxConnectionsSizePerQuery()); - connection.getShardingDataSource().getShardingContext().getMetaData().getTable().put( - logicTableName, tableMetaDataLoader.load(logicTableName, connection.getShardingDataSource().getShardingContext().getShardingRule())); + @Override + public ResultSet getGeneratedKeys() throws SQLException { + Optional generatedKey = getGeneratedKey(); + if (preparedStatementExecutor.isReturnGeneratedKeys() && generatedKey.isPresent()) { + return new GeneratedKeysResultSet(routeResult.getGeneratedKey().getGeneratedKeys().iterator(), generatedKey.get().getColumn().getName(), this); + } + if (1 == preparedStatementExecutor.getStatements().size()) { + return preparedStatementExecutor.getStatements().iterator().next().getGeneratedKeys(); } + return new GeneratedKeysResultSet(); } - @Override - public void clearBatch() { - currentResultSet = null; - clearParameters(); - batchStatementUnits.clear(); - batchCount = 0; + private Optional getGeneratedKey() { + if (null != routeResult && routeResult.getSqlStatement() instanceof InsertStatement) { + return Optional.fromNullable(routeResult.getGeneratedKey()); + } + return Optional.absent(); } @Override - public void addBatch() throws SQLException { - try { - for (BatchPreparedStatementExecuteUnit each : routeBatch()) { - each.getStatement().addBatch(); - each.mapAddBatchCount(batchCount); - } - batchCount++; - } finally { - currentResultSet = null; - clearParameters(); + public ResultSet getResultSet() throws SQLException { + if (null != currentResultSet) { + return currentResultSet; } - } - - private List routeBatch() throws SQLException { - List result = new ArrayList<>(); - sqlRoute(); - for (RouteUnit each : routeResult.getRouteUnits()) { - BatchPreparedStatementExecuteUnit batchStatementUnit = getBatchPreparedStatementExecuteUnit(each); - replaySetParameter(batchStatementUnit.getStatement(), each.getSqlUnit().getParameterSets().get(0)); - result.add(batchStatementUnit); + if (1 == preparedStatementExecutor.getStatements().size() && routeResult.getSqlStatement() instanceof DQLStatement) { + currentResultSet = preparedStatementExecutor.getStatements().iterator().next().getResultSet(); + return currentResultSet; } - return result; - } - - private void sqlRoute() { - routeResult = routingEngine.route(getParameters()); + List resultSets = new ArrayList<>(preparedStatementExecutor.getStatements().size()); + List queryResults = new ArrayList<>(preparedStatementExecutor.getStatements().size()); + for (Statement each : preparedStatementExecutor.getStatements()) { + ResultSet resultSet = each.getResultSet(); + resultSets.add(resultSet); + queryResults.add(new StreamQueryResult(resultSet)); + } + if (routeResult.getSqlStatement() instanceof SelectStatement || routeResult.getSqlStatement() instanceof DALStatement) { + MergeEngine mergeEngine = MergeEngineFactory.newInstance( + connection.getShardingContext().getShardingRule(), queryResults, routeResult.getSqlStatement(), + connection.getShardingContext().getMetaData().getTable()); + currentResultSet = new ShardingResultSet(resultSets, mergeEngine.merge(), this); + } + return currentResultSet; } - private PreparedStatementExecutor getPreparedStatementExecutor() throws SQLException { - DatabaseType databaseType = connection.getShardingDataSource().getShardingContext().getDatabaseType(); - SQLExecuteTemplate sqlExecuteTemplate = new SQLExecuteTemplate(connection.getShardingDataSource().getShardingContext().getExecuteEngine()); - if (ConnectionMode.MEMORY_STRICTLY == connection.getShardingDataSource().getShardingContext().getConnectionMode()) { - return new MemoryStrictlyPreparedStatementExecutor(databaseType, routeResult.getSqlStatement().getType(), sqlExecuteTemplate, getExecuteUnitsForMemoryStrictly()); + // TODO refresh table meta data by SQL parse result + private void refreshTableMetaData() throws SQLException { + if (null != routeResult && null != connection && SQLType.DDL == routeResult.getSqlStatement().getType() && !routeResult.getSqlStatement().getTables().isEmpty()) { + String logicTableName = routeResult.getSqlStatement().getTables().getSingleTableName(); + TableMetaDataLoader tableMetaDataLoader = new TableMetaDataLoader(connection.getShardingContext().getMetaData().getDataSource(), + connection.getShardingContext().getExecuteEngine(), new JDBCTableMetaDataConnectionManager(connection.getDataSourceMap()), + connection.getShardingContext().getMaxConnectionsSizePerQuery()); + connection.getShardingContext().getMetaData().getTable().put( + logicTableName, tableMetaDataLoader.load(logicTableName, connection.getShardingContext().getShardingRule())); } - return new ConnectionStrictlyPreparedStatementExecutor(databaseType, routeResult.getSqlStatement().getType(), sqlExecuteTemplate, getExecuteUnitsForConnectionStrictly()); } - private Collection getExecuteUnitsForMemoryStrictly() throws SQLException { - Collection result = new LinkedList<>(); - for (RouteUnit each : routeResult.getRouteUnits()) { - result.add(getPreparedStatementExecuteUnit(connection.getConnection(each.getDataSourceName()), each)); - } - return result; + private void initPreparedStatementExecutor() throws SQLException { + preparedStatementExecutor.init(routeResult); + setParametersForStatements(); } - @SuppressWarnings("unchecked") - private Collection> getExecuteUnitsForConnectionStrictly() throws SQLException { - SQLExecutePrepareTemplate sqlExecutePrepareTemplate = new SQLExecutePrepareTemplate(connection.getShardingDataSource().getShardingContext().getMaxConnectionsSizePerQuery()); - return (Collection) sqlExecutePrepareTemplate.getExecuteUnitGroups(routeResult.getRouteUnits(), new SQLExecutePrepareCallback() { - - @Override - public Connection getConnection(final String dataSourceName) throws SQLException { - return ShardingPreparedStatement.this.connection.getConnection(dataSourceName); - } - - @Override - public SQLExecuteUnit createSQLExecuteUnit(final Connection connection, final RouteUnit routeUnit) throws SQLException { - return getPreparedStatementExecuteUnit(connection, routeUnit); - } - }); + private void setParametersForStatements() { + for (int i = 0; i < preparedStatementExecutor.getStatements().size(); i++) { + replaySetParameter((PreparedStatement) preparedStatementExecutor.getStatements().get(i), preparedStatementExecutor.getParameterSets().get(i)); + } } - private PreparedStatementExecuteUnit getPreparedStatementExecuteUnit(final Connection connection, final RouteUnit routeUnit) throws SQLException { - PreparedStatement preparedStatement = createPreparedStatement(connection, routeUnit.getSqlUnit().getSql()); - routedStatements.add(preparedStatement); - replaySetParameter(preparedStatement, routeUnit.getSqlUnit().getParameterSets().get(0)); - return new PreparedStatementExecuteUnit(routeUnit, preparedStatement); + private void clearPrevious() throws SQLException { + preparedStatementExecutor.clear(); } - private BatchPreparedStatementExecuteUnit getBatchPreparedStatementExecuteUnit(final RouteUnit routeUnit) throws SQLException { - Optional preparedBatchStatement = Iterators.tryFind(batchStatementUnits.iterator(), new Predicate() { - - @Override - public boolean apply(final BatchPreparedStatementExecuteUnit input) { - return Objects.equals(input.getRouteUnit(), routeUnit); - } - }); - if (preparedBatchStatement.isPresent()) { - preparedBatchStatement.get().getRouteUnit().getSqlUnit().getParameterSets().add(routeUnit.getSqlUnit().getParameterSets().get(0)); - return preparedBatchStatement.get(); + @Override + public void addBatch() { + try { + sqlRoute(); + batchPreparedStatementExecutor.addBatchForRouteUnits(routeResult); + } finally { + currentResultSet = null; + clearParameters(); } - BatchPreparedStatementExecuteUnit result = new BatchPreparedStatementExecuteUnit( - routeUnit, createPreparedStatement(connection.getConnection(routeUnit.getDataSourceName()), routeUnit.getSqlUnit().getSql())); - batchStatementUnits.add(result); - return result; } - private PreparedStatement createPreparedStatement(final Connection connection, final String sql) throws SQLException { - return returnGeneratedKeys ? connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + private void sqlRoute() { + routeResult = routingEngine.route(new ArrayList<>(getParameters())); } @Override public int[] executeBatch() throws SQLException { try { - SQLExecuteTemplate sqlExecuteTemplate = new SQLExecuteTemplate(connection.getShardingDataSource().getShardingContext().getExecuteEngine()); - if (ConnectionMode.MEMORY_STRICTLY == connection.getShardingDataSource().getShardingContext().getConnectionMode()) { - return new MemoryStrictlyBatchPreparedStatementExecutor(connection.getShardingDataSource().getShardingContext().getDatabaseType(), - routeResult.getSqlStatement().getType(), batchCount, sqlExecuteTemplate, batchStatementUnits).executeBatch(); - } - return new ConnectionStrictlyBatchPreparedStatementExecutor(connection.getShardingDataSource().getShardingContext().getDatabaseType(), - routeResult.getSqlStatement().getType(), batchCount, sqlExecuteTemplate, partitionBatchPreparedStatementUnitGroups()).executeBatch(); + initBatchPreparedStatementExecutor(); + return batchPreparedStatementExecutor.executeBatch(); } finally { clearBatch(); } } - private List> partitionBatchPreparedStatementUnitGroups() { - List> result = new LinkedList<>(); - for (List each : getBatchPreparedStatementUnitGroups().values()) { - int desiredPartitionSize = Math.max(each.size() / connection.getShardingDataSource().getShardingContext().getMaxConnectionsSizePerQuery(), 1); - result.addAll(Lists.partition(each, desiredPartitionSize)); - } - return result; + private void initBatchPreparedStatementExecutor() throws SQLException { + batchPreparedStatementExecutor.init(); + setBatchParametersForStatements(); } - private Map> getBatchPreparedStatementUnitGroups() { - Map> result = new HashMap<>(batchStatementUnits.size(), 1); - for (BatchPreparedStatementExecuteUnit each : batchStatementUnits) { - String dataSourceName = each.getRouteUnit().getDataSourceName(); - if (!result.containsKey(dataSourceName)) { - result.put(dataSourceName, new LinkedList()); + private void setBatchParametersForStatements() throws SQLException { + for (Statement each : batchPreparedStatementExecutor.getStatements()) { + List> parameterSet = batchPreparedStatementExecutor.getParameterSet(each); + for (List parameters : parameterSet) { + replaySetParameter((PreparedStatement) each, parameters); + ((PreparedStatement) each).addBatch(); } - result.get(dataSourceName).add(each); } - return result; } @Override - public ResultSet getGeneratedKeys() throws SQLException { - Optional generatedKey = getGeneratedKey(); - if (returnGeneratedKeys && generatedKey.isPresent()) { - return new GeneratedKeysResultSet(routeResult.getGeneratedKey().getGeneratedKeys().iterator(), generatedKey.get().getColumn().getName(), this); - } - if (1 == routedStatements.size()) { - return routedStatements.iterator().next().getGeneratedKeys(); - } - return new GeneratedKeysResultSet(); + public void clearBatch() throws SQLException { + currentResultSet = null; + batchPreparedStatementExecutor.clear(); + clearParameters(); } - private Optional getGeneratedKey() { - if (null != routeResult && routeResult.getSqlStatement() instanceof InsertStatement) { - return Optional.fromNullable(routeResult.getGeneratedKey()); - } - return Optional.absent(); + @SuppressWarnings("MagicConstant") + @Override + public int getResultSetType() { + return preparedStatementExecutor.getResultSetType(); } + @SuppressWarnings("MagicConstant") @Override - public ResultSet getResultSet() throws SQLException { - if (null != currentResultSet) { - return currentResultSet; - } - if (1 == routedStatements.size() && routeResult.getSqlStatement() instanceof DQLStatement) { - currentResultSet = routedStatements.iterator().next().getResultSet(); - return currentResultSet; - } - List resultSets = new ArrayList<>(routedStatements.size()); - List queryResults = new ArrayList<>(routedStatements.size()); - for (PreparedStatement each : routedStatements) { - ResultSet resultSet = each.getResultSet(); - resultSets.add(resultSet); - queryResults.add(new StreamQueryResult(resultSet)); - } - if (routeResult.getSqlStatement() instanceof SelectStatement || routeResult.getSqlStatement() instanceof DALStatement) { - MergeEngine mergeEngine = MergeEngineFactory.newInstance( - connection.getShardingDataSource().getShardingContext().getShardingRule(), queryResults, routeResult.getSqlStatement(), - connection.getShardingDataSource().getShardingContext().getMetaData().getTable()); - currentResultSet = new ShardingResultSet(resultSets, mergeEngine.merge(), this); - } - return currentResultSet; + public int getResultSetConcurrency() { + return preparedStatementExecutor.getResultSetConcurrency(); + } + + @Override + public int getResultSetHoldability() { + return preparedStatementExecutor.getResultSetHoldability(); + } + + @Override + public Collection getRoutedStatements() { + return Collections2.transform(preparedStatementExecutor.getStatements(), new Function() { + @Override + public PreparedStatement apply(final Statement input) { + return (PreparedStatement) input; + } + }); } } + + + + + diff --git a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/ShardingStatement.java b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/ShardingStatement.java index 5c24c867defd4..0d58fd2415204 100644 --- a/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/ShardingStatement.java +++ b/sharding-jdbc/src/main/java/io/shardingsphere/core/jdbc/core/statement/ShardingStatement.java @@ -18,20 +18,9 @@ package io.shardingsphere.core.jdbc.core.statement; import com.google.common.base.Optional; -import io.shardingsphere.core.constant.ConnectionMode; -import io.shardingsphere.core.constant.DatabaseType; import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.ShardingExecuteGroup; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; -import io.shardingsphere.core.executor.sql.execute.result.MemoryQueryResult; +import io.shardingsphere.core.executor.StatementExecutor; import io.shardingsphere.core.executor.sql.execute.result.StreamQueryResult; -import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareCallback; -import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareTemplate; -import io.shardingsphere.core.executor.statement.ConnectionStrictlyStatementExecutor; -import io.shardingsphere.core.executor.statement.MemoryStrictlyStatementExecutor; -import io.shardingsphere.core.executor.statement.StatementExecuteUnit; -import io.shardingsphere.core.executor.statement.StatementExecutor; import io.shardingsphere.core.jdbc.adapter.AbstractStatementAdapter; import io.shardingsphere.core.jdbc.core.ShardingContext; import io.shardingsphere.core.jdbc.core.connection.ShardingConnection; @@ -46,20 +35,16 @@ import io.shardingsphere.core.parsing.parser.sql.dml.insert.InsertStatement; import io.shardingsphere.core.parsing.parser.sql.dql.DQLStatement; import io.shardingsphere.core.parsing.parser.sql.dql.select.SelectStatement; -import io.shardingsphere.core.routing.RouteUnit; import io.shardingsphere.core.routing.SQLRouteResult; import io.shardingsphere.core.routing.StatementRoutingEngine; import io.shardingsphere.core.routing.router.sharding.GeneratedKey; -import lombok.AccessLevel; import lombok.Getter; -import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedList; import java.util.List; /** @@ -71,26 +56,17 @@ * @author zhaojun * @author panjuan */ -@Getter public final class ShardingStatement extends AbstractStatementAdapter { + @Getter private final ShardingConnection connection; - private final int resultSetType; + private final StatementExecutor statementExecutor; - private final int resultSetConcurrency; - - private final int resultSetHoldability; - - private final Collection routedStatements = new LinkedList<>(); - - @Getter(AccessLevel.NONE) private boolean returnGeneratedKeys; - @Getter(AccessLevel.NONE) private SQLRouteResult routeResult; - @Getter(AccessLevel.NONE) private ResultSet currentResultSet; public ShardingStatement(final ShardingConnection connection) { @@ -104,9 +80,7 @@ public ShardingStatement(final ShardingConnection connection, final int resultSe public ShardingStatement(final ShardingConnection connection, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { super(Statement.class); this.connection = connection; - this.resultSetType = resultSetType; - this.resultSetConcurrency = resultSetConcurrency; - this.resultSetHoldability = resultSetHoldability; + statementExecutor = new StatementExecutor(resultSetType, resultSetConcurrency, resultSetHoldability, connection); } @Override @@ -115,11 +89,11 @@ public ResultSet executeQuery(final String sql) throws SQLException { try { clearPrevious(); sqlRoute(sql); - List resultSets = getStatementExecutor().executeQuery(); + initStatementExecutor(); MergeEngine mergeEngine = MergeEngineFactory.newInstance( - connection.getShardingDataSource().getShardingContext().getShardingRule(), getQueryResults(resultSets), - routeResult.getSqlStatement(), connection.getShardingDataSource().getShardingContext().getMetaData().getTable()); - result = new ShardingResultSet(resultSets, mergeEngine.merge(), this); + connection.getShardingContext().getShardingRule(), statementExecutor.executeQuery(), + routeResult.getSqlStatement(), connection.getShardingContext().getMetaData().getTable()); + result = new ShardingResultSet(statementExecutor.getResultSets(), mergeEngine.merge(), this); } finally { currentResultSet = null; } @@ -127,24 +101,13 @@ public ResultSet executeQuery(final String sql) throws SQLException { return result; } - private List getQueryResults(final List resultSets) throws SQLException { - List result = new ArrayList<>(resultSets.size()); - for (ResultSet each : resultSets) { - if (ConnectionMode.MEMORY_STRICTLY == connection.getShardingDataSource().getShardingContext().getConnectionMode()) { - result.add(new StreamQueryResult(each)); - } else { - result.add(new MemoryQueryResult(each)); - } - } - return result; - } - @Override public int executeUpdate(final String sql) throws SQLException { try { clearPrevious(); sqlRoute(sql); - return getStatementExecutor().executeUpdate(); + initStatementExecutor(); + return statementExecutor.executeUpdate(); } finally { refreshTableMetaData(); currentResultSet = null; @@ -159,7 +122,8 @@ public int executeUpdate(final String sql, final int autoGeneratedKeys) throws S try { clearPrevious(); sqlRoute(sql); - return getStatementExecutor().executeUpdate(autoGeneratedKeys); + initStatementExecutor(); + return statementExecutor.executeUpdate(autoGeneratedKeys); } finally { currentResultSet = null; } @@ -171,7 +135,8 @@ public int executeUpdate(final String sql, final int[] columnIndexes) throws SQL try { clearPrevious(); sqlRoute(sql); - return getStatementExecutor().executeUpdate(columnIndexes); + initStatementExecutor(); + return statementExecutor.executeUpdate(columnIndexes); } finally { currentResultSet = null; } @@ -183,7 +148,8 @@ public int executeUpdate(final String sql, final String[] columnNames) throws SQ try { clearPrevious(); sqlRoute(sql); - return getStatementExecutor().executeUpdate(columnNames); + initStatementExecutor(); + return statementExecutor.executeUpdate(columnNames); } finally { currentResultSet = null; } @@ -194,7 +160,8 @@ public boolean execute(final String sql) throws SQLException { try { clearPrevious(); sqlRoute(sql); - return getStatementExecutor().execute(); + initStatementExecutor(); + return statementExecutor.execute(); } finally { refreshTableMetaData(); currentResultSet = null; @@ -209,7 +176,8 @@ public boolean execute(final String sql, final int autoGeneratedKeys) throws SQL try { clearPrevious(); sqlRoute(sql); - return getStatementExecutor().execute(autoGeneratedKeys); + initStatementExecutor(); + return statementExecutor.execute(autoGeneratedKeys); } finally { currentResultSet = null; } @@ -221,7 +189,8 @@ public boolean execute(final String sql, final int[] columnIndexes) throws SQLEx try { clearPrevious(); sqlRoute(sql); - return getStatementExecutor().execute(columnIndexes); + initStatementExecutor(); + return statementExecutor.execute(columnIndexes); } finally { currentResultSet = null; } @@ -233,62 +202,51 @@ public boolean execute(final String sql, final String[] columnNames) throws SQLE try { clearPrevious(); sqlRoute(sql); - return getStatementExecutor().execute(columnNames); + initStatementExecutor(); + return statementExecutor.execute(columnNames); } finally { currentResultSet = null; } } - private StatementExecutor getStatementExecutor() throws SQLException { - DatabaseType databaseType = connection.getShardingDataSource().getShardingContext().getDatabaseType(); - SQLExecuteTemplate sqlExecuteTemplate = new SQLExecuteTemplate(connection.getShardingDataSource().getShardingContext().getExecuteEngine()); - if (ConnectionMode.MEMORY_STRICTLY == connection.getShardingDataSource().getShardingContext().getConnectionMode()) { - return new MemoryStrictlyStatementExecutor(databaseType, routeResult.getSqlStatement().getType(), sqlExecuteTemplate, getExecuteUnitsForMemoryStrictly()); + @Override + public ResultSet getResultSet() throws SQLException { + if (null != currentResultSet) { + return currentResultSet; } - return new ConnectionStrictlyStatementExecutor(databaseType, routeResult.getSqlStatement().getType(), sqlExecuteTemplate, getExecuteUnitsForConnectionStrictly()); - } - - private Collection getExecuteUnitsForMemoryStrictly() throws SQLException { - Collection result = new LinkedList<>(); - for (RouteUnit each : routeResult.getRouteUnits()) { - result.add(getStatementExecuteUnit(connection.getConnection(each.getDataSourceName()), each)); + if (1 == statementExecutor.getStatements().size() && routeResult.getSqlStatement() instanceof DQLStatement) { + currentResultSet = statementExecutor.getStatements().iterator().next().getResultSet(); + return currentResultSet; } - return result; - } - - @SuppressWarnings("unchecked") - private Collection> getExecuteUnitsForConnectionStrictly() throws SQLException { - SQLExecutePrepareTemplate sqlExecutePrepareTemplate = new SQLExecutePrepareTemplate(connection.getShardingDataSource().getShardingContext().getMaxConnectionsSizePerQuery()); - return (Collection) sqlExecutePrepareTemplate.getExecuteUnitGroups(routeResult.getRouteUnits(), new SQLExecutePrepareCallback() { - - @Override - public Connection getConnection(final String dataSourceName) throws SQLException { - return ShardingStatement.this.connection.getConnection(dataSourceName); - } - - @Override - public SQLExecuteUnit createSQLExecuteUnit(final Connection connection, final RouteUnit routeUnit) throws SQLException { - return getStatementExecuteUnit(connection, routeUnit); - } - }); + List resultSets = new ArrayList<>(statementExecutor.getStatements().size()); + List queryResults = new ArrayList<>(statementExecutor.getStatements().size()); + for (Statement each : statementExecutor.getStatements()) { + ResultSet resultSet = each.getResultSet(); + resultSets.add(resultSet); + queryResults.add(new StreamQueryResult(resultSet)); + } + if (routeResult.getSqlStatement() instanceof SelectStatement || routeResult.getSqlStatement() instanceof DALStatement) { + MergeEngine mergeEngine = MergeEngineFactory.newInstance( + connection.getShardingContext().getShardingRule(), queryResults, routeResult.getSqlStatement(), + connection.getShardingContext().getMetaData().getTable()); + currentResultSet = new ShardingResultSet(resultSets, mergeEngine.merge(), this); + } + return currentResultSet; } - private StatementExecuteUnit getStatementExecuteUnit(final Connection connection, final RouteUnit routeUnit) throws SQLException { - Statement statement = connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); - routedStatements.add(statement); - replayMethodsInvocation(statement); - return new StatementExecuteUnit(routeUnit, statement); + private void initStatementExecutor() throws SQLException { + statementExecutor.init(routeResult); + replayMethodForStatements(); } - private void clearPrevious() throws SQLException { - for (Statement each : routedStatements) { - each.close(); + private void replayMethodForStatements() { + for (Statement each : statementExecutor.getStatements()) { + replayMethodsInvocation(each); } - routedStatements.clear(); } private void sqlRoute(final String sql) { - ShardingContext shardingContext = connection.getShardingDataSource().getShardingContext(); + ShardingContext shardingContext = connection.getShardingContext(); routeResult = new StatementRoutingEngine(shardingContext.getShardingRule(), shardingContext.getMetaData().getTable(), shardingContext.getDatabaseType(), shardingContext.isShowSQL(), shardingContext.getMetaData().getDataSource()).route(sql); } @@ -297,14 +255,40 @@ private void sqlRoute(final String sql) { private void refreshTableMetaData() throws SQLException { if (null != routeResult && null != connection && SQLType.DDL == routeResult.getSqlStatement().getType() && !routeResult.getSqlStatement().getTables().isEmpty()) { String logicTableName = routeResult.getSqlStatement().getTables().getSingleTableName(); - TableMetaDataLoader tableMetaDataLoader = new TableMetaDataLoader(connection.getShardingDataSource().getShardingContext().getMetaData().getDataSource(), - connection.getShardingDataSource().getShardingContext().getExecuteEngine(), new JDBCTableMetaDataConnectionManager(connection.getShardingDataSource().getDataSourceMap()), - connection.getShardingDataSource().getShardingContext().getMaxConnectionsSizePerQuery()); - connection.getShardingDataSource().getShardingContext().getMetaData().getTable().put( - logicTableName, tableMetaDataLoader.load(logicTableName, connection.getShardingDataSource().getShardingContext().getShardingRule())); + TableMetaDataLoader tableMetaDataLoader = new TableMetaDataLoader(connection.getShardingContext().getMetaData().getDataSource(), + connection.getShardingContext().getExecuteEngine(), new JDBCTableMetaDataConnectionManager(connection.getDataSourceMap()), + connection.getShardingContext().getMaxConnectionsSizePerQuery()); + connection.getShardingContext().getMetaData().getTable().put( + logicTableName, tableMetaDataLoader.load(logicTableName, connection.getShardingContext().getShardingRule())); } } + private void clearPrevious() throws SQLException { + statementExecutor.clear(); + } + + @SuppressWarnings("MagicConstant") + @Override + public int getResultSetType() { + return statementExecutor.getResultSetType(); + } + + @SuppressWarnings("MagicConstant") + @Override + public int getResultSetConcurrency() { + return statementExecutor.getResultSetConcurrency(); + } + + @Override + public int getResultSetHoldability() { + return statementExecutor.getResultSetHoldability(); + } + + @Override + public Collection getRoutedStatements() { + return statementExecutor.getStatements(); + } + @Override public ResultSet getGeneratedKeys() throws SQLException { Optional generatedKey = getGeneratedKey(); @@ -323,29 +307,5 @@ private Optional getGeneratedKey() { } return Optional.absent(); } - - @Override - public ResultSet getResultSet() throws SQLException { - if (null != currentResultSet) { - return currentResultSet; - } - if (1 == routedStatements.size() && routeResult.getSqlStatement() instanceof DQLStatement) { - currentResultSet = routedStatements.iterator().next().getResultSet(); - return currentResultSet; - } - List resultSets = new ArrayList<>(routedStatements.size()); - List queryResults = new ArrayList<>(routedStatements.size()); - for (Statement each : routedStatements) { - ResultSet resultSet = each.getResultSet(); - resultSets.add(resultSet); - queryResults.add(new StreamQueryResult(resultSet)); - } - if (routeResult.getSqlStatement() instanceof SelectStatement || routeResult.getSqlStatement() instanceof DALStatement) { - MergeEngine mergeEngine = MergeEngineFactory.newInstance( - connection.getShardingDataSource().getShardingContext().getShardingRule(), queryResults, routeResult.getSqlStatement(), - connection.getShardingDataSource().getShardingContext().getMetaData().getTable()); - currentResultSet = new ShardingResultSet(resultSets, mergeEngine.merge(), this); - } - return currentResultSet; - } } + diff --git a/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/AbstractBaseExecutorTest.java b/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/AbstractBaseExecutorTest.java index 86e2f9b024a3b..5b09bbaf7fabd 100644 --- a/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/AbstractBaseExecutorTest.java +++ b/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/AbstractBaseExecutorTest.java @@ -17,14 +17,16 @@ package io.shardingsphere.core.executor; +import io.shardingsphere.core.constant.DatabaseType; import io.shardingsphere.core.event.ShardingEventBusInstance; import io.shardingsphere.core.executor.fixture.EventCaller; import io.shardingsphere.core.executor.fixture.ExecutorTestUtil; import io.shardingsphere.core.executor.fixture.TestDMLExecutionEventListener; import io.shardingsphere.core.executor.fixture.TestDQLExecutionEventListener; import io.shardingsphere.core.executor.fixture.TestOverallExecutionEventListener; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; +import io.shardingsphere.core.jdbc.core.ShardingContext; +import io.shardingsphere.core.jdbc.core.connection.ShardingConnection; import lombok.AccessLevel; import lombok.Getter; import org.junit.After; @@ -32,12 +34,21 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + @Getter(AccessLevel.PROTECTED) public abstract class AbstractBaseExecutorTest { private ShardingExecuteEngine executeEngine; - private SQLExecuteTemplate executeTemplate; + private ShardingConnection connection; @Mock private EventCaller eventCaller; @@ -49,19 +60,36 @@ public abstract class AbstractBaseExecutorTest { private TestOverallExecutionEventListener overallExecutionEventListener; @Before - public void setUp() { + public void setUp() throws SQLException, ReflectiveOperationException { MockitoAnnotations.initMocks(this); ExecutorExceptionHandler.setExceptionThrown(false); executeEngine = new ShardingExecuteEngine(Runtime.getRuntime().availableProcessors()); - executeTemplate = new SQLExecuteTemplate(executeEngine); overallExecutionEventListener = new TestOverallExecutionEventListener(eventCaller); dqlExecutionEventListener = new TestDQLExecutionEventListener(eventCaller); dmlExecutionEventListener = new TestDMLExecutionEventListener(eventCaller); + setConnection(); + register(); + } + + private void register() { ShardingEventBusInstance.getInstance().register(overallExecutionEventListener); ShardingEventBusInstance.getInstance().register(dqlExecutionEventListener); ShardingEventBusInstance.getInstance().register(dmlExecutionEventListener); } + private void setConnection() throws SQLException { + ShardingContext shardingContext = mock(ShardingContext.class); + when(shardingContext.getExecuteEngine()).thenReturn(executeEngine); + when(shardingContext.getMaxConnectionsSizePerQuery()).thenReturn(1); + when(shardingContext.getDatabaseType()).thenReturn(DatabaseType.H2); + DataSource dataSource = mock(DataSource.class); + when(dataSource.getConnection()).thenReturn(mock(Connection.class)); + Map dataSourceSourceMap = new LinkedHashMap<>(); + dataSourceSourceMap.put("ds_0", dataSource); + dataSourceSourceMap.put("ds_1", dataSource); + connection = new ShardingConnection(dataSourceSourceMap, shardingContext); + } + @After public void tearDown() throws ReflectiveOperationException { ExecutorTestUtil.clear(); diff --git a/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/BatchPreparedStatementExecutorTest.java b/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/BatchPreparedStatementExecutorTest.java index 9bff8d6ae53d5..001a7bd1f472d 100644 --- a/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/BatchPreparedStatementExecutorTest.java +++ b/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/BatchPreparedStatementExecutorTest.java @@ -17,23 +17,24 @@ package io.shardingsphere.core.executor; -import io.shardingsphere.core.constant.DatabaseType; +import io.shardingsphere.core.constant.ConnectionMode; import io.shardingsphere.core.constant.SQLType; import io.shardingsphere.core.event.ShardingEventType; -import io.shardingsphere.core.executor.batch.BatchPreparedStatementExecutor; -import io.shardingsphere.core.executor.batch.BatchPreparedStatementExecuteUnit; -import io.shardingsphere.core.executor.batch.MemoryStrictlyBatchPreparedStatementExecutor; -import io.shardingsphere.core.rewrite.SQLBuilder; +import io.shardingsphere.core.routing.BatchRouteUnit; import io.shardingsphere.core.routing.RouteUnit; +import io.shardingsphere.core.routing.SQLUnit; import org.junit.Test; +import java.lang.reflect.Field; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; +import java.util.List; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @@ -46,135 +47,138 @@ public final class BatchPreparedStatementExecutorTest extends AbstractBaseExecut private static final String SQL = "DELETE FROM table_x WHERE id=?"; + private BatchPreparedStatementExecutor actual; + + @Override + public void setUp() throws SQLException, ReflectiveOperationException { + super.setUp(); + actual = new BatchPreparedStatementExecutor(1, 1, 1, false, getConnection()); + } + + private void setSQLType(final SQLType sqlType) throws ReflectiveOperationException { + Field field = BatchPreparedStatementExecutor.class.getSuperclass().getDeclaredField("sqlType"); + field.setAccessible(true); + field.set(actual, sqlType); + } + + private void setExecuteGroups(final List preparedStatements) throws ReflectiveOperationException { + Collection> executeGroups = new LinkedList<>(); + List preparedStatementExecuteUnits = new LinkedList<>(); + executeGroups.add(new ShardingExecuteGroup<>(preparedStatementExecuteUnits)); + Collection routeUnits = new LinkedList<>(); + for (PreparedStatement each : preparedStatements) { + List> parameterSets = new LinkedList<>(); + parameterSets.add(Collections.singletonList((Object) 1)); + RouteUnit routeUnit = new RouteUnit("ds_0", new SQLUnit(SQL, parameterSets)); + BatchRouteUnit batchRouteUnit = new BatchRouteUnit(routeUnit); + batchRouteUnit.mapAddBatchCount(0); + batchRouteUnit.mapAddBatchCount(1); + routeUnits.add(batchRouteUnit); + preparedStatementExecuteUnits.add(new StatementExecuteUnit(routeUnit, each, ConnectionMode.MEMORY_STRICTLY)); + } + setFields(executeGroups, routeUnits); + } + + private void setFields( + final Collection> executeGroups, final Collection routeUnits) throws NoSuchFieldException, IllegalAccessException { + Field field = BatchPreparedStatementExecutor.class.getSuperclass().getDeclaredField("executeGroups"); + field.setAccessible(true); + field.set(actual, executeGroups); + field = BatchPreparedStatementExecutor.class.getDeclaredField("routeUnits"); + field.setAccessible(true); + field.set(actual, routeUnits); + field = BatchPreparedStatementExecutor.class.getDeclaredField("batchCount"); + field.setAccessible(true); + field.set(actual, 2); + } + @SuppressWarnings("unchecked") @Test - public void assertNoPreparedStatement() throws SQLException { - BatchPreparedStatementExecutor actual = new MemoryStrictlyBatchPreparedStatementExecutor( - DatabaseType.H2, SQLType.DML, 2, getExecuteTemplate(), Collections.emptyList()); + public void assertNoPreparedStatement() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement = getPreparedStatement(); + when(preparedStatement.executeBatch()).thenReturn(new int[] {0, 0}); + setSQLType(SQLType.DQL); + setExecuteGroups(Collections.singletonList(preparedStatement)); assertThat(actual.executeBatch(), is(new int[] {0, 0})); } @Test - public void assertExecuteBatchForSinglePreparedStatementSuccess() throws SQLException { - PreparedStatement preparedStatement = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteBatchForSinglePreparedStatementSuccess() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement = getPreparedStatement(); when(preparedStatement.executeBatch()).thenReturn(new int[] {10, 20}); - when(preparedStatement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - BatchPreparedStatementExecutor actual = new MemoryStrictlyBatchPreparedStatementExecutor( - DatabaseType.H2, SQLType.DML, 2, getExecuteTemplate(), createBatchPreparedStatementExecuteUnits(SQL, preparedStatement, "ds_0", 2)); + setSQLType(SQLType.DQL); + setExecuteGroups(Collections.singletonList(preparedStatement)); assertThat(actual.executeBatch(), is(new int[] {10, 20})); verify(preparedStatement).executeBatch(); - verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(4)).verifySQL(SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList(1)); - verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList(2)); - verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); - verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); + verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); + verify(getEventCaller(), times(2)).verifySQL(SQL); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); + verify(getEventCaller(), times(1)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); + verify(getEventCaller(), times(1)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } - @Test - public void assertExecuteBatchForMultiplePreparedStatementsSuccess() throws SQLException { - PreparedStatement preparedStatement1 = mock(PreparedStatement.class); - PreparedStatement preparedStatement2 = mock(PreparedStatement.class); + private PreparedStatement getPreparedStatement() throws SQLException { + PreparedStatement statement = mock(PreparedStatement.class); Connection connection = mock(Connection.class); DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:ds_master;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MYSQL"); + when(connection.getMetaData()).thenReturn(databaseMetaData); + when(statement.getConnection()).thenReturn(connection); + return statement; + } + + @Test + public void assertExecuteBatchForMultiplePreparedStatementsSuccess() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement1 = getPreparedStatement(); + PreparedStatement preparedStatement2 = getPreparedStatement(); when(preparedStatement1.executeBatch()).thenReturn(new int[] {10, 20}); when(preparedStatement2.executeBatch()).thenReturn(new int[] {20, 40}); - when(preparedStatement1.getConnection()).thenReturn(connection); - when(preparedStatement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - BatchPreparedStatementExecutor actual = new MemoryStrictlyBatchPreparedStatementExecutor(DatabaseType.H2, SQLType.DML, 2, getExecuteTemplate(), - createBatchPreparedStatementExecuteUnits(SQL, preparedStatement1, "ds_0", preparedStatement2, "ds_1", 2)); + setSQLType(SQLType.DQL); + setExecuteGroups(Arrays.asList(preparedStatement1, preparedStatement2)); assertThat(actual.executeBatch(), is(new int[] {30, 60})); verify(preparedStatement1).executeBatch(); verify(preparedStatement2).executeBatch(); verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(4)).verifyDataSource("ds_1"); - verify(getEventCaller(), times(8)).verifySQL(SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList(1)); - verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList(2)); - verify(getEventCaller(), times(4)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); - verify(getEventCaller(), times(4)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); + verify(getEventCaller(), times(4)).verifySQL(SQL); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); + verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); + verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteBatchForSinglePreparedStatementFailure() throws SQLException { - PreparedStatement preparedStatement = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteBatchForSinglePreparedStatementFailure() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement = getPreparedStatement(); SQLException exp = new SQLException(); when(preparedStatement.executeBatch()).thenThrow(exp); - when(preparedStatement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - BatchPreparedStatementExecutor actual = new MemoryStrictlyBatchPreparedStatementExecutor(DatabaseType.H2, SQLType.DML, 2, getExecuteTemplate(), - createBatchPreparedStatementExecuteUnits(SQL, preparedStatement, "ds_0", 2)); + setSQLType(SQLType.DQL); + setExecuteGroups(Collections.singletonList(preparedStatement)); assertThat(actual.executeBatch(), is(new int[] {0, 0})); verify(preparedStatement).executeBatch(); - verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(4)).verifySQL(SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList(1)); - verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList(2)); - verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); - verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); - verify(getEventCaller(), times(2)).verifyException(exp); + verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); + verify(getEventCaller(), times(2)).verifySQL(SQL); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); + verify(getEventCaller(), times(1)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); + verify(getEventCaller(), times(1)).verifyException(exp); } @Test - public void assertExecuteBatchForMultiplePreparedStatementsFailure() throws SQLException { - PreparedStatement preparedStatement1 = mock(PreparedStatement.class); - PreparedStatement preparedStatement2 = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteBatchForMultiplePreparedStatementsFailure() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement1 = getPreparedStatement(); + PreparedStatement preparedStatement2 = getPreparedStatement(); SQLException exp = new SQLException(); when(preparedStatement1.executeBatch()).thenThrow(exp); when(preparedStatement2.executeBatch()).thenThrow(exp); - when(preparedStatement1.getConnection()).thenReturn(connection); - when(preparedStatement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - BatchPreparedStatementExecutor actual = new MemoryStrictlyBatchPreparedStatementExecutor(DatabaseType.H2, SQLType.DML, 2, getExecuteTemplate(), - createBatchPreparedStatementExecuteUnits(SQL, preparedStatement1, "ds_0", preparedStatement2, "ds_1", 2)); + setSQLType(SQLType.DQL); + setExecuteGroups(Arrays.asList(preparedStatement1, preparedStatement2)); assertThat(actual.executeBatch(), is(new int[] {0, 0})); verify(preparedStatement1).executeBatch(); verify(preparedStatement2).executeBatch(); verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(4)).verifyDataSource("ds_1"); - verify(getEventCaller(), times(8)).verifySQL(SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList(1)); - verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList(2)); - verify(getEventCaller(), times(4)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); - verify(getEventCaller(), times(4)).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); - verify(getEventCaller(), times(4)).verifyException(exp); - } - - private Collection createBatchPreparedStatementExecuteUnits( - final String sql, final PreparedStatement preparedStatement, final String dataSource, final int addBatchTimes) { - SQLBuilder sqlBuilder = new SQLBuilder(); - sqlBuilder.appendLiterals(sql); - BatchPreparedStatementExecuteUnit batchPreparedStatementExecuteUnit = - new BatchPreparedStatementExecuteUnit(new RouteUnit(dataSource, sqlBuilder.toSQL(null, Collections.emptyMap(), null, null)), preparedStatement); - batchPreparedStatementExecuteUnit.getRouteUnit().getSqlUnit().getParameterSets().clear(); - for (int i = 0; i < addBatchTimes; i++) { - batchPreparedStatementExecuteUnit.getRouteUnit().getSqlUnit().getParameterSets().add(Collections.singletonList(i + 1)); - batchPreparedStatementExecuteUnit.mapAddBatchCount(i); - } - Collection result = new LinkedList<>(); - result.add(batchPreparedStatementExecuteUnit); - return result; - } - - private Collection createBatchPreparedStatementExecuteUnits( - final String sql, final PreparedStatement preparedStatement1, final String dataSource1, final PreparedStatement preparedStatement2, final String dataSource2, final int addBatchTimes) { - Collection result = new LinkedList<>(); - result.addAll(createBatchPreparedStatementExecuteUnits(sql, preparedStatement1, dataSource1, addBatchTimes)); - result.addAll(createBatchPreparedStatementExecuteUnits(sql, preparedStatement2, dataSource2, addBatchTimes)); - return result; + verify(getEventCaller(), times(4)).verifySQL(SQL); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); + verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); + verify(getEventCaller(), times(2)).verifyException(exp); } } diff --git a/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/PreparedStatementExecutorTest.java b/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/PreparedStatementExecutorTest.java index f0dc7b8aa5f14..2ceaae88067f7 100644 --- a/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/PreparedStatementExecutorTest.java +++ b/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/PreparedStatementExecutorTest.java @@ -17,16 +17,15 @@ package io.shardingsphere.core.executor; -import io.shardingsphere.core.constant.DatabaseType; +import io.shardingsphere.core.constant.ConnectionMode; import io.shardingsphere.core.constant.SQLType; import io.shardingsphere.core.event.ShardingEventType; -import io.shardingsphere.core.executor.prepared.MemoryStrictlyPreparedStatementExecutor; -import io.shardingsphere.core.executor.prepared.PreparedStatementExecutor; -import io.shardingsphere.core.executor.prepared.PreparedStatementExecuteUnit; -import io.shardingsphere.core.rewrite.SQLBuilder; +import io.shardingsphere.core.merger.QueryResult; import io.shardingsphere.core.routing.RouteUnit; +import io.shardingsphere.core.routing.SQLUnit; import org.junit.Test; +import java.lang.reflect.Field; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; @@ -38,7 +37,6 @@ import java.util.LinkedList; import java.util.List; -import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; @@ -54,369 +52,311 @@ public final class PreparedStatementExecutorTest extends AbstractBaseExecutorTes private static final String DML_SQL = "DELETE FROM table_x"; - @SuppressWarnings("unchecked") + private PreparedStatementExecutor actual; + + @Override + public void setUp() throws SQLException, ReflectiveOperationException { + super.setUp(); + actual = new PreparedStatementExecutor(1, 1, 1, false, getConnection()); + } + + private void setSQLType(final SQLType sqlType) throws ReflectiveOperationException { + Field field = PreparedStatementExecutor.class.getSuperclass().getDeclaredField("sqlType"); + field.setAccessible(true); + field.set(actual, sqlType); + } + + private void setExecuteGroups(final List preparedStatements, final SQLType sqlType) throws ReflectiveOperationException { + Collection> executeGroups = new LinkedList<>(); + List preparedStatementExecuteUnits = new LinkedList<>(); + executeGroups.add(new ShardingExecuteGroup<>(preparedStatementExecuteUnits)); + for (PreparedStatement each : preparedStatements) { + List> parameterSets = new LinkedList<>(); + String sql = SQLType.DQL.equals(sqlType) ? DQL_SQL : DML_SQL; + parameterSets.add(Collections.singletonList((Object) 1)); + preparedStatementExecuteUnits.add(new StatementExecuteUnit(new RouteUnit("ds_0", new SQLUnit(sql, parameterSets)), each, ConnectionMode.MEMORY_STRICTLY)); + } + Field field = PreparedStatementExecutor.class.getSuperclass().getDeclaredField("executeGroups"); + field.setAccessible(true); + field.set(actual, executeGroups); + } + @Test public void assertNoStatement() throws SQLException { - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor(DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), Collections.emptyList()); assertFalse(actual.execute()); assertThat(actual.executeUpdate(), is(0)); assertThat(actual.executeQuery().size(), is(0)); } @Test - public void assertExecuteQueryForSinglePreparedStatementSuccess() throws SQLException { - PreparedStatement preparedStatement = mock(PreparedStatement.class); + public void assertExecuteQueryForSinglePreparedStatementSuccess() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement = getPreparedStatement(); ResultSet resultSet = mock(ResultSet.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + when(resultSet.getInt(1)).thenReturn(1); when(preparedStatement.executeQuery()).thenReturn(resultSet); - when(preparedStatement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createPreparedStatementExecuteUnits(DQL_SQL, preparedStatement, "ds_0")); - assertThat(actual.executeQuery(), is(Collections.singletonList(resultSet))); + setSQLType(SQLType.DQL); + setExecuteGroups(Collections.singletonList(preparedStatement), SQLType.DQL); + assertThat((int) actual.executeQuery().iterator().next().getValue(1, int.class), is(resultSet.getInt(1))); verify(preparedStatement).executeQuery(); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } + private PreparedStatement getPreparedStatement() throws SQLException { + PreparedStatement statement = mock(PreparedStatement.class); + Connection connection = mock(Connection.class); + DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); + when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:ds_master;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MYSQL"); + when(connection.getMetaData()).thenReturn(databaseMetaData); + when(statement.getConnection()).thenReturn(connection); + return statement; + } + @Test - public void assertExecuteQueryForMultiplePreparedStatementsSuccess() throws SQLException { - PreparedStatement preparedStatement1 = mock(PreparedStatement.class); - PreparedStatement preparedStatement2 = mock(PreparedStatement.class); + public void assertExecuteQueryForMultiplePreparedStatementsSuccess() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement1 = getPreparedStatement(); + PreparedStatement preparedStatement2 = getPreparedStatement(); ResultSet resultSet1 = mock(ResultSet.class); ResultSet resultSet2 = mock(ResultSet.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + when(resultSet1.getInt(1)).thenReturn(1); + when(resultSet2.getInt(1)).thenReturn(2); when(preparedStatement1.executeQuery()).thenReturn(resultSet1); when(preparedStatement2.executeQuery()).thenReturn(resultSet2); - when(preparedStatement1.getConnection()).thenReturn(connection); - when(preparedStatement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createPreparedStatementExecuteUnits(DQL_SQL, preparedStatement1, "ds_0", preparedStatement2, "ds_1")); - List actualResultSets = actual.executeQuery(); - assertThat(actualResultSets, hasItem(resultSet1)); - assertThat(actualResultSets, hasItem(resultSet2)); + setSQLType(SQLType.DQL); + setExecuteGroups(Arrays.asList(preparedStatement1, preparedStatement2), SQLType.DQL); + List result = actual.executeQuery(); + List resultSets = Arrays.asList(resultSet1, resultSet2); + for (int i = 0; i < result.size(); i++) { + assertThat((int) result.get(i).getValue(1, int.class), is(resultSets.get(i).getInt(1))); + } verify(preparedStatement1).executeQuery(); verify(preparedStatement2).executeQuery(); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteQueryForSinglePreparedStatementFailure() throws SQLException { - PreparedStatement preparedStatement = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteQueryForSinglePreparedStatementFailure() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement = getPreparedStatement(); SQLException exp = new SQLException(); when(preparedStatement.executeQuery()).thenThrow(exp); - when(preparedStatement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createPreparedStatementExecuteUnits(DQL_SQL, preparedStatement, "ds_0")); - assertThat(actual.executeQuery(), is(Collections.singletonList((ResultSet) null))); + setSQLType(SQLType.DQL); + setExecuteGroups(Collections.singletonList(preparedStatement), SQLType.DQL); + assertThat(actual.executeQuery(), is(Collections.singletonList((QueryResult) null))); verify(preparedStatement).executeQuery(); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller()).verifyException(exp); } @Test - public void assertExecuteQueryForMultiplePreparedStatementsFailure() throws SQLException { - PreparedStatement preparedStatement1 = mock(PreparedStatement.class); - PreparedStatement preparedStatement2 = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteQueryForMultiplePreparedStatementsFailure() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement1 = getPreparedStatement(); + PreparedStatement preparedStatement2 = getPreparedStatement(); SQLException exp = new SQLException(); when(preparedStatement1.executeQuery()).thenThrow(exp); when(preparedStatement2.executeQuery()).thenThrow(exp); - when(preparedStatement1.getConnection()).thenReturn(connection); - when(preparedStatement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createPreparedStatementExecuteUnits(DQL_SQL, preparedStatement1, "ds_0", preparedStatement2, "ds_1")); - List actualResultSets = actual.executeQuery(); - assertThat(actualResultSets, is(Arrays.asList((ResultSet) null, null))); + setSQLType(SQLType.DQL); + setExecuteGroups(Arrays.asList(preparedStatement1, preparedStatement2), SQLType.DQL); + List actualResultSets = actual.executeQuery(); + assertThat(actualResultSets, is(Arrays.asList((QueryResult) null, null))); verify(preparedStatement1).executeQuery(); verify(preparedStatement2).executeQuery(); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller(), times(2)).verifyException(exp); } @Test - public void assertExecuteUpdateForSinglePreparedStatementSuccess() throws SQLException { - PreparedStatement preparedStatement = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteUpdateForSinglePreparedStatementSuccess() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement = getPreparedStatement(); when(preparedStatement.executeUpdate()).thenReturn(10); - when(preparedStatement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createPreparedStatementExecuteUnits(DML_SQL, preparedStatement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(preparedStatement), SQLType.DML); assertThat(actual.executeUpdate(), is(10)); verify(preparedStatement).executeUpdate(); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteUpdateForMultiplePreparedStatementsSuccess() throws SQLException { - PreparedStatement preparedStatement1 = mock(PreparedStatement.class); - PreparedStatement preparedStatement2 = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteUpdateForMultiplePreparedStatementsSuccess() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement1 = getPreparedStatement(); + PreparedStatement preparedStatement2 = getPreparedStatement(); when(preparedStatement1.executeUpdate()).thenReturn(10); when(preparedStatement2.executeUpdate()).thenReturn(20); - when(preparedStatement1.getConnection()).thenReturn(connection); - when(preparedStatement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createPreparedStatementExecuteUnits(DML_SQL, preparedStatement1, "ds_0", preparedStatement2, "ds_1")); + setSQLType(SQLType.DML); + setExecuteGroups(Arrays.asList(preparedStatement1, preparedStatement2), SQLType.DML); assertThat(actual.executeUpdate(), is(30)); verify(preparedStatement1).executeUpdate(); verify(preparedStatement2).executeUpdate(); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DML_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteUpdateForSinglePreparedStatementFailure() throws SQLException { - PreparedStatement preparedStatement = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteUpdateForSinglePreparedStatementFailure() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement = getPreparedStatement(); SQLException exp = new SQLException(); when(preparedStatement.executeUpdate()).thenThrow(exp); - when(preparedStatement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createPreparedStatementExecuteUnits(DML_SQL, preparedStatement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(preparedStatement), SQLType.DML); assertThat(actual.executeUpdate(), is(0)); verify(preparedStatement).executeUpdate(); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller()).verifyException(exp); } @Test - public void assertExecuteUpdateForMultiplePreparedStatementsFailure() throws SQLException { - PreparedStatement preparedStatement1 = mock(PreparedStatement.class); - PreparedStatement preparedStatement2 = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteUpdateForMultiplePreparedStatementsFailure() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement1 = getPreparedStatement(); + PreparedStatement preparedStatement2 = getPreparedStatement(); SQLException exp = new SQLException(); when(preparedStatement1.executeUpdate()).thenThrow(exp); when(preparedStatement2.executeUpdate()).thenThrow(exp); - when(preparedStatement1.getConnection()).thenReturn(connection); - when(preparedStatement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createPreparedStatementExecuteUnits(DML_SQL, preparedStatement1, "ds_0", preparedStatement2, "ds_1")); + setSQLType(SQLType.DML); + setExecuteGroups(Arrays.asList(preparedStatement1, preparedStatement2), SQLType.DML); assertThat(actual.executeUpdate(), is(0)); verify(preparedStatement1).executeUpdate(); verify(preparedStatement2).executeUpdate(); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DML_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller(), times(2)).verifyException(exp); } @Test - public void assertExecuteForSinglePreparedStatementSuccessWithDML() throws SQLException { - PreparedStatement preparedStatement = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForSinglePreparedStatementSuccessWithDML() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement = getPreparedStatement(); when(preparedStatement.execute()).thenReturn(false); - when(preparedStatement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createPreparedStatementExecuteUnits(DML_SQL, preparedStatement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(preparedStatement), SQLType.DML); assertFalse(actual.execute()); verify(preparedStatement).execute(); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteForMultiplePreparedStatementsSuccessWithDML() throws SQLException { - PreparedStatement preparedStatement1 = mock(PreparedStatement.class); - PreparedStatement preparedStatement2 = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForMultiplePreparedStatementsSuccessWithDML() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement1 = getPreparedStatement(); + PreparedStatement preparedStatement2 = getPreparedStatement(); when(preparedStatement1.execute()).thenReturn(false); when(preparedStatement2.execute()).thenReturn(false); - when(preparedStatement1.getConnection()).thenReturn(connection); - when(preparedStatement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createPreparedStatementExecuteUnits(DML_SQL, preparedStatement1, "ds_0", preparedStatement2, "ds_1")); + setSQLType(SQLType.DML); + setExecuteGroups(Arrays.asList(preparedStatement1, preparedStatement2), SQLType.DML); assertFalse(actual.execute()); verify(preparedStatement1).execute(); verify(preparedStatement2).execute(); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DML_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteForSinglePreparedStatementFailureWithDML() throws SQLException { - PreparedStatement preparedStatement = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForSinglePreparedStatementFailureWithDML() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement = getPreparedStatement(); SQLException exp = new SQLException(); when(preparedStatement.execute()).thenThrow(exp); - when(preparedStatement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createPreparedStatementExecuteUnits(DML_SQL, preparedStatement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(preparedStatement), SQLType.DML); assertFalse(actual.execute()); verify(preparedStatement).execute(); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller()).verifyException(exp); } @Test - public void assertExecuteForMultiplePreparedStatementsFailureWithDML() throws SQLException { - PreparedStatement preparedStatement1 = mock(PreparedStatement.class); - PreparedStatement preparedStatement2 = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForMultiplePreparedStatementsFailureWithDML() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement1 = getPreparedStatement(); + PreparedStatement preparedStatement2 = getPreparedStatement(); SQLException exp = new SQLException(); when(preparedStatement1.execute()).thenThrow(exp); when(preparedStatement2.execute()).thenThrow(exp); - when(preparedStatement1.getConnection()).thenReturn(connection); - when(preparedStatement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createPreparedStatementExecuteUnits(DML_SQL, preparedStatement1, "ds_0", preparedStatement2, "ds_1")); + setSQLType(SQLType.DML); + setExecuteGroups(Arrays.asList(preparedStatement1, preparedStatement2), SQLType.DML); assertFalse(actual.execute()); verify(preparedStatement1).execute(); verify(preparedStatement2).execute(); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DML_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller(), times(2)).verifyException(exp); } @Test - public void assertExecuteForSinglePreparedStatementWithDQL() throws SQLException { - PreparedStatement preparedStatement = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForSinglePreparedStatementWithDQL() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement = getPreparedStatement(); when(preparedStatement.execute()).thenReturn(true); - when(preparedStatement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createPreparedStatementExecuteUnits(DQL_SQL, preparedStatement, "ds_0")); + setSQLType(SQLType.DQL); + setExecuteGroups(Collections.singletonList(preparedStatement), SQLType.DQL); assertTrue(actual.execute()); verify(preparedStatement).execute(); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteForMultiplePreparedStatements() throws SQLException { - PreparedStatement preparedStatement1 = mock(PreparedStatement.class); - PreparedStatement preparedStatement2 = mock(PreparedStatement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForMultiplePreparedStatements() throws SQLException, ReflectiveOperationException { + PreparedStatement preparedStatement1 = getPreparedStatement(); + PreparedStatement preparedStatement2 = getPreparedStatement(); when(preparedStatement1.execute()).thenReturn(true); when(preparedStatement2.execute()).thenReturn(true); - when(preparedStatement1.getConnection()).thenReturn(connection); - when(preparedStatement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - PreparedStatementExecutor actual = new MemoryStrictlyPreparedStatementExecutor( - DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createPreparedStatementExecuteUnits(DQL_SQL, preparedStatement1, "ds_0", preparedStatement2, "ds_1")); + setSQLType(SQLType.DQL); + setExecuteGroups(Arrays.asList(preparedStatement1, preparedStatement2), SQLType.DQL); assertTrue(actual.execute()); verify(preparedStatement1).execute(); verify(preparedStatement2).execute(); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } - - private Collection createPreparedStatementExecuteUnits(final String sql, final PreparedStatement preparedStatement, final String dataSource) { - Collection result = new LinkedList<>(); - SQLBuilder sqlBuilder = new SQLBuilder(); - sqlBuilder.appendLiterals(sql); - result.add(new PreparedStatementExecuteUnit(new RouteUnit(dataSource, sqlBuilder.toSQL(null, Collections.emptyMap(), null, null)), preparedStatement)); - return result; - } - - private Collection createPreparedStatementExecuteUnits( - final String sql, final PreparedStatement preparedStatement1, final String dataSource1, final PreparedStatement preparedStatement2, final String dataSource2) { - Collection result = new LinkedList<>(); - result.addAll(createPreparedStatementExecuteUnits(sql, preparedStatement1, dataSource1)); - result.addAll(createPreparedStatementExecuteUnits(sql, preparedStatement2, dataSource2)); - return result; - } } diff --git a/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/StatementExecutorTest.java b/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/StatementExecutorTest.java index 5ebbf77c95c0b..df3fde090a8ac 100644 --- a/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/StatementExecutorTest.java +++ b/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/StatementExecutorTest.java @@ -17,17 +17,16 @@ package io.shardingsphere.core.executor; -import io.shardingsphere.core.constant.DatabaseType; +import io.shardingsphere.core.constant.ConnectionMode; import io.shardingsphere.core.constant.SQLType; import io.shardingsphere.core.event.ShardingEventType; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; -import io.shardingsphere.core.executor.statement.MemoryStrictlyStatementExecutor; -import io.shardingsphere.core.executor.statement.StatementExecuteUnit; -import io.shardingsphere.core.executor.statement.StatementExecutor; -import io.shardingsphere.core.rewrite.SQLBuilder; +import io.shardingsphere.core.merger.QueryResult; import io.shardingsphere.core.routing.RouteUnit; +import io.shardingsphere.core.routing.SQLUnit; import org.junit.Test; +import java.lang.reflect.Field; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; @@ -39,7 +38,6 @@ import java.util.LinkedList; import java.util.List; -import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; @@ -50,485 +48,411 @@ import static org.mockito.Mockito.when; public final class StatementExecutorTest extends AbstractBaseExecutorTest { - + private static final String DQL_SQL = "SELECT * FROM table_x"; private static final String DML_SQL = "DELETE FROM table_x"; + private StatementExecutor actual; + + @Override + public void setUp() throws SQLException, ReflectiveOperationException { + super.setUp(); + actual = new StatementExecutor(1, 1, 1, getConnection()); + } + @Test public void assertNoStatement() throws SQLException { - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), Collections.emptyList()); assertFalse(actual.execute()); assertThat(actual.executeUpdate(), is(0)); assertThat(actual.executeQuery().size(), is(0)); } @Test - public void assertExecuteQueryForSingleStatementSuccess() throws SQLException { - Statement statement = mock(Statement.class); + public void assertExecuteQueryForSingleStatementSuccess() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); ResultSet resultSet = mock(ResultSet.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); - when(connection.getMetaData()).thenReturn(databaseMetaData); + when(resultSet.getInt(1)).thenReturn(1); when(statement.executeQuery(DQL_SQL)).thenReturn(resultSet); - when(statement.getConnection()).thenReturn(connection); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createStatementExecuteUnits(DQL_SQL, statement, "ds_0")); - assertThat(actual.executeQuery(), is(Collections.singletonList(resultSet))); + setSQLType(SQLType.DQL); + setExecuteGroups(Collections.singletonList(statement), SQLType.DQL); + assertThat((int) actual.executeQuery().iterator().next().getValue(1, int.class), is(resultSet.getInt(1))); verify(statement).executeQuery(DQL_SQL); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); - verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); - verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); - verify(getEventCaller(), times(0)).verifyException(null); + } + + private void setSQLType(final SQLType sqlType) throws ReflectiveOperationException { + Field field = StatementExecutor.class.getSuperclass().getDeclaredField("sqlType"); + field.setAccessible(true); + field.set(actual, sqlType); + } + + private void setExecuteGroups(final List statements, final SQLType sqlType) throws ReflectiveOperationException { + Collection> executeGroups = new LinkedList<>(); + List statementExecuteUnits = new LinkedList<>(); + executeGroups.add(new ShardingExecuteGroup<>(statementExecuteUnits)); + for (Statement each : statements) { + List> parameterSets = new LinkedList<>(); + String sql = SQLType.DQL.equals(sqlType) ? DQL_SQL : DML_SQL; + parameterSets.add(Collections.singletonList((Object) 1)); + statementExecuteUnits.add(new StatementExecuteUnit(new RouteUnit("ds_0", new SQLUnit(sql, parameterSets)), each, ConnectionMode.MEMORY_STRICTLY)); + } + Field field = StatementExecutor.class.getSuperclass().getDeclaredField("executeGroups"); + field.setAccessible(true); + field.set(actual, executeGroups); } @Test - public void assertExecuteQueryForMultipleStatementsSuccess() throws SQLException { - Statement statement1 = mock(Statement.class); - Statement statement2 = mock(Statement.class); + public void assertExecuteQueryForMultipleStatementsSuccess() throws SQLException, ReflectiveOperationException { + Statement statement1 = getStatement(); + Statement statement2 = getStatement(); ResultSet resultSet1 = mock(ResultSet.class); ResultSet resultSet2 = mock(ResultSet.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); - when(connection.getMetaData()).thenReturn(databaseMetaData); + when(resultSet1.getInt(1)).thenReturn(1); + when(resultSet2.getInt(1)).thenReturn(2); when(statement1.executeQuery(DQL_SQL)).thenReturn(resultSet1); - when(statement1.getConnection()).thenReturn(connection); when(statement2.executeQuery(DQL_SQL)).thenReturn(resultSet2); - when(statement2.getConnection()).thenReturn(connection); - StatementExecutor actual = new MemoryStrictlyStatementExecutor( - DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createStatementExecuteUnits(DQL_SQL, statement1, "ds_0", statement2, "ds_1")); - List actualResultSets = actual.executeQuery(); - assertThat(actualResultSets, hasItem(resultSet1)); - assertThat(actualResultSets, hasItem(resultSet2)); + setSQLType(SQLType.DQL); + setExecuteGroups(Arrays.asList(statement1, statement2), SQLType.DQL); + List result = actual.executeQuery(); + List resultSets = Arrays.asList(resultSet1, resultSet2); + for (int i = 0; i < result.size(); i++) { + assertThat((int) result.get(i).getValue(1, int.class), is(resultSets.get(i).getInt(1))); + } verify(statement1).executeQuery(DQL_SQL); verify(statement2).executeQuery(DQL_SQL); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); - verify(getEventCaller(), times(4)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); - verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); - verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteQueryForSingleStatementFailure() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteQueryForSingleStatementFailure() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); SQLException exp = new SQLException(); - when(connection.getMetaData()).thenReturn(databaseMetaData); when(statement.executeQuery(DQL_SQL)).thenThrow(exp); - when(statement.getConnection()).thenReturn(connection); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createStatementExecuteUnits(DQL_SQL, statement, "ds_0")); - assertThat(actual.executeQuery(), is(Collections.singletonList((ResultSet) null))); + setSQLType(SQLType.DQL); + setExecuteGroups(Collections.singletonList(statement), SQLType.DQL); + assertThat(actual.executeQuery(), is(Collections.singletonList((QueryResult) null))); verify(statement).executeQuery(DQL_SQL); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); - verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); - verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller()).verifyException(exp); } @Test - public void assertExecuteQueryForMultipleStatementsFailure() throws SQLException { - Statement statement1 = mock(Statement.class); - Statement statement2 = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteQueryForMultipleStatementsFailure() throws SQLException, ReflectiveOperationException { + Statement statement1 = getStatement(); + Statement statement2 = getStatement(); SQLException exp = new SQLException(); when(statement1.executeQuery(DQL_SQL)).thenThrow(exp); when(statement2.executeQuery(DQL_SQL)).thenThrow(exp); - when(statement1.getConnection()).thenReturn(connection); - when(statement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor( - DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createStatementExecuteUnits(DQL_SQL, statement1, "ds_0", statement2, "ds_1")); - List actualResultSets = actual.executeQuery(); - assertThat(actualResultSets, is(Arrays.asList((ResultSet) null, null))); + setSQLType(SQLType.DQL); + setExecuteGroups(Arrays.asList(statement1, statement2), SQLType.DQL); + List actualResultSets = actual.executeQuery(); + assertThat(actualResultSets, is(Arrays.asList((QueryResult) null, null))); verify(statement1).executeQuery(DQL_SQL); verify(statement2).executeQuery(DQL_SQL); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller(), times(2)).verifyException(exp); } @Test - public void assertExecuteUpdateForSingleStatementSuccess() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteUpdateForSingleStatementSuccess() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); when(statement.executeUpdate(DML_SQL)).thenReturn(10); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); assertThat(actual.executeUpdate(), is(10)); verify(statement).executeUpdate(DML_SQL); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteUpdateForMultipleStatementsSuccess() throws SQLException { - Statement statement1 = mock(Statement.class); - Statement statement2 = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteUpdateForMultipleStatementsSuccess() throws SQLException, ReflectiveOperationException { + Statement statement1 = getStatement(); + Statement statement2 = getStatement(); when(statement1.executeUpdate(DML_SQL)).thenReturn(10); when(statement2.executeUpdate(DML_SQL)).thenReturn(20); - when(statement1.getConnection()).thenReturn(connection); - when(statement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement1, "ds_0", statement2, "ds_1")); + setSQLType(SQLType.DML); + setExecuteGroups(Arrays.asList(statement1, statement2), SQLType.DML); assertThat(actual.executeUpdate(), is(30)); verify(statement1).executeUpdate(DML_SQL); verify(statement2).executeUpdate(DML_SQL); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DML_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteUpdateForSingleStatementFailure() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteUpdateForSingleStatementFailure() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); SQLException exp = new SQLException(); when(statement.executeUpdate(DML_SQL)).thenThrow(exp); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); assertThat(actual.executeUpdate(), is(0)); verify(statement).executeUpdate(DML_SQL); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller()).verifyException(exp); } @Test - public void assertExecuteUpdateForMultipleStatementsFailure() throws SQLException { - Statement statement1 = mock(Statement.class); - Statement statement2 = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteUpdateForMultipleStatementsFailure() throws SQLException, ReflectiveOperationException { + Statement statement1 = getStatement(); + Statement statement2 = getStatement(); SQLException exp = new SQLException(); when(statement1.executeUpdate(DML_SQL)).thenThrow(exp); when(statement2.executeUpdate(DML_SQL)).thenThrow(exp); - when(statement1.getConnection()).thenReturn(connection); - when(statement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement1, "ds_0", statement2, "ds_1")); + setSQLType(SQLType.DML); + setExecuteGroups(Arrays.asList(statement1, statement2), SQLType.DML); assertThat(actual.executeUpdate(), is(0)); verify(statement1).executeUpdate(DML_SQL); verify(statement2).executeUpdate(DML_SQL); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DML_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller(), times(2)).verifyException(exp); } @Test - public void assertExecuteUpdateWithAutoGeneratedKeys() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteUpdateWithAutoGeneratedKeys() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); when(statement.executeUpdate(DML_SQL, Statement.NO_GENERATED_KEYS)).thenReturn(10); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); assertThat(actual.executeUpdate(Statement.NO_GENERATED_KEYS), is(10)); verify(statement).executeUpdate(DML_SQL, Statement.NO_GENERATED_KEYS); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteUpdateWithColumnIndexes() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); + public void assertExecuteUpdateWithColumnIndexes() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); when(statement.executeUpdate(DML_SQL, new int[] {1})).thenReturn(10); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); assertThat(actual.executeUpdate(new int[] {1}), is(10)); verify(statement).executeUpdate(DML_SQL, new int[] {1}); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } - @Test - public void assertExecuteUpdateWithColumnNames() throws SQLException { + private Statement getStatement() throws SQLException { Statement statement = mock(Statement.class); Connection connection = mock(Connection.class); DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(statement.executeUpdate(DML_SQL, new String[] {"col"})).thenReturn(10); - when(statement.getConnection()).thenReturn(connection); + when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:ds_master;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MYSQL"); when(connection.getMetaData()).thenReturn(databaseMetaData); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + when(statement.getConnection()).thenReturn(connection); + return statement; + } + + @Test + public void assertExecuteUpdateWithColumnNames() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); + when(statement.executeUpdate(DML_SQL, new String[] {"col"})).thenReturn(10); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); assertThat(actual.executeUpdate(new String[] {"col"}), is(10)); verify(statement).executeUpdate(DML_SQL, new String[] {"col"}); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteForSingleStatementSuccessWithDML() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForSingleStatementSuccessWithDML() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); when(statement.execute(DML_SQL)).thenReturn(false); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); assertFalse(actual.execute()); verify(statement).execute(DML_SQL); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteForMultipleStatementsSuccessWithDML() throws SQLException { - Statement statement1 = mock(Statement.class); - Statement statement2 = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForMultipleStatementsSuccessWithDML() throws SQLException, ReflectiveOperationException { + Statement statement1 = getStatement(); + Statement statement2 = getStatement(); when(statement1.execute(DML_SQL)).thenReturn(false); when(statement2.execute(DML_SQL)).thenReturn(false); - when(statement1.getConnection()).thenReturn(connection); - when(statement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement1, "ds_0", statement2, "ds_1")); + setSQLType(SQLType.DML); + setExecuteGroups(Arrays.asList(statement1, statement2), SQLType.DML); assertFalse(actual.execute()); verify(statement1).execute(DML_SQL); verify(statement2).execute(DML_SQL); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DML_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteForSingleStatementFailureWithDML() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForSingleStatementFailureWithDML() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); SQLException exp = new SQLException(); when(statement.execute(DML_SQL)).thenThrow(exp); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); assertFalse(actual.execute()); verify(statement).execute(DML_SQL); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller()).verifyException(exp); } @Test - public void assertExecuteForMultipleStatementsFailureWithDML() throws SQLException { - Statement statement1 = mock(Statement.class); - Statement statement2 = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForMultipleStatementsFailureWithDML() throws SQLException, ReflectiveOperationException { + Statement statement1 = getStatement(); + Statement statement2 = getStatement(); SQLException exp = new SQLException(); when(statement1.execute(DML_SQL)).thenThrow(exp); when(statement2.execute(DML_SQL)).thenThrow(exp); - when(statement1.getConnection()).thenReturn(connection); - when(statement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor( - DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement1, "ds_0", statement2, "ds_1")); + setSQLType(SQLType.DML); + setExecuteGroups(Arrays.asList(statement1, statement2), SQLType.DML); assertFalse(actual.execute()); verify(statement1).execute(DML_SQL); verify(statement2).execute(DML_SQL); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DML_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); verify(getEventCaller(), times(2)).verifyException(exp); } @Test - public void assertExecuteForSingleStatementWithDQL() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForSingleStatementWithDQL() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); when(statement.execute(DQL_SQL)).thenReturn(true); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createStatementExecuteUnits(DQL_SQL, statement, "ds_0")); + setSQLType(SQLType.DQL); + setExecuteGroups(Collections.singletonList(statement), SQLType.DQL); assertTrue(actual.execute()); verify(statement).execute(DQL_SQL); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteForMultipleStatements() throws SQLException { - Statement statement1 = mock(Statement.class); - Statement statement2 = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteForMultipleStatements() throws SQLException, ReflectiveOperationException { + Statement statement1 = getStatement(); + Statement statement2 = getStatement(); when(statement1.execute(DQL_SQL)).thenReturn(true); when(statement2.execute(DQL_SQL)).thenReturn(true); - when(statement1.getConnection()).thenReturn(connection); - when(statement2.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor( - DatabaseType.H2, SQLType.DQL, getExecuteTemplate(), createStatementExecuteUnits(DQL_SQL, statement1, "ds_0", statement2, "ds_1")); + setSQLType(SQLType.DQL); + setExecuteGroups(Arrays.asList(statement1, statement2), SQLType.DQL); assertTrue(actual.execute()); verify(statement1).execute(DQL_SQL); verify(statement2).execute(DQL_SQL); - verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); - verify(getEventCaller(), times(2)).verifyDataSource("ds_1"); + verify(getEventCaller(), times(4)).verifyDataSource("ds_0"); verify(getEventCaller(), times(4)).verifySQL(DQL_SQL); - verify(getEventCaller(), times(4)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(4)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller(), times(2)).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteWithAutoGeneratedKeys() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteWithAutoGeneratedKeys() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); when(statement.execute(DML_SQL, Statement.NO_GENERATED_KEYS)).thenReturn(false); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); assertFalse(actual.execute(Statement.NO_GENERATED_KEYS)); verify(statement).execute(DML_SQL, Statement.NO_GENERATED_KEYS); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteWithColumnIndexes() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteWithColumnIndexes() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); when(statement.execute(DML_SQL, new int[] {1})).thenReturn(false); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); assertFalse(actual.execute(new int[] {1})); verify(statement).execute(DML_SQL, new int[] {1}); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertExecuteWithColumnNames() throws SQLException { - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + public void assertExecuteWithColumnNames() throws SQLException, ReflectiveOperationException { + Statement statement = getStatement(); when(statement.execute(DML_SQL, new String[] {"col"})).thenReturn(false); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); assertFalse(actual.execute(new String[] {"col"})); verify(statement).execute(DML_SQL, new String[] {"col"}); verify(getEventCaller(), times(2)).verifyDataSource("ds_0"); verify(getEventCaller(), times(2)).verifySQL(DML_SQL); - verify(getEventCaller(), times(2)).verifyParameters(Collections.emptyList()); + verify(getEventCaller(), times(2)).verifyParameters(Collections.singletonList((Object) 1)); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_SUCCESS); verify(getEventCaller(), times(0)).verifyException(null); } @Test - public void assertOverallExceptionFailure() throws SQLException { + public void assertOverallExceptionFailure() throws SQLException, ReflectiveOperationException { ExecutorExceptionHandler.setExceptionThrown(true); - Statement statement = mock(Statement.class); - Connection connection = mock(Connection.class); - DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class); - when(databaseMetaData.getURL()).thenReturn("jdbc:h2:mem:test_db"); + Statement statement = getStatement(); SQLException exp = new SQLException(); when(statement.execute(DML_SQL)).thenThrow(exp); - when(statement.getConnection()).thenReturn(connection); - when(connection.getMetaData()).thenReturn(databaseMetaData); - StatementExecutor actual = new MemoryStrictlyStatementExecutor(DatabaseType.H2, SQLType.DML, getExecuteTemplate(), createStatementExecuteUnits(DML_SQL, statement, "ds_0")); + setSQLType(SQLType.DML); + setExecuteGroups(Collections.singletonList(statement), SQLType.DML); try { assertFalse(actual.execute()); } catch (final SQLException ignore) { @@ -536,20 +460,4 @@ public void assertOverallExceptionFailure() throws SQLException { verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.BEFORE_EXECUTE); verify(getEventCaller()).verifyEventExecutionType(ShardingEventType.EXECUTE_FAILURE); } - - private Collection createStatementExecuteUnits(final String sql, final Statement statement, final String dataSource) { - Collection result = new LinkedList<>(); - SQLBuilder sqlBuilder = new SQLBuilder(); - sqlBuilder.appendLiterals(sql); - result.add(new StatementExecuteUnit(new RouteUnit(dataSource, sqlBuilder.toSQL(null, Collections.emptyMap(), null, null)), statement)); - return result; - } - - private Collection createStatementExecuteUnits( - final String sql, final Statement statement1, final String dataSource1, final Statement statement2, final String dataSource2) { - Collection result = new LinkedList<>(); - result.addAll(createStatementExecuteUnits(sql, statement1, dataSource1)); - result.addAll(createStatementExecuteUnits(sql, statement2, dataSource2)); - return result; - } } diff --git a/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/fixture/ExecutorTestUtil.java b/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/fixture/ExecutorTestUtil.java index 13b8575262ead..5da0f178cc355 100644 --- a/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/fixture/ExecutorTestUtil.java +++ b/sharding-jdbc/src/test/java/io/shardingsphere/core/executor/fixture/ExecutorTestUtil.java @@ -20,7 +20,6 @@ import io.shardingsphere.core.event.ShardingEventType; import io.shardingsphere.core.event.root.RootInvokeEvent; import io.shardingsphere.core.event.executor.SQLExecutionEvent; -import io.shardingsphere.core.event.root.RootInvokeStartEvent; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -53,7 +52,6 @@ public static void listen(final EventCaller eventCaller, final SQLExecutionEvent * @param event overall execution event */ public static void listen(final EventCaller eventCaller, final RootInvokeEvent event) { - eventCaller.verifyIsParallelExecute(((RootInvokeStartEvent) event).isParallelExecute()); if (ShardingEventType.EXECUTE_FAILURE == event.getEventType()) { eventCaller.verifyException(event.getException()); } diff --git a/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/ConnectionAdapterTest.java b/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/ConnectionAdapterTest.java index 277544164ec37..b42cd882a7cb6 100644 --- a/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/ConnectionAdapterTest.java +++ b/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/ConnectionAdapterTest.java @@ -17,6 +17,7 @@ package io.shardingsphere.core.jdbc.adapter; +import com.google.common.collect.Multimap; import io.shardingsphere.core.common.base.AbstractShardingJDBCDatabaseAndTableTest; import io.shardingsphere.core.jdbc.core.connection.ShardingConnection; import io.shardingsphere.core.jdbc.util.JDBCTestSQL; @@ -26,7 +27,6 @@ import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.Map; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertNull; @@ -49,7 +49,7 @@ public void assertSetAutoCommit() throws SQLException { private void assertAutoCommit(final ShardingConnection actual, final boolean autoCommit) throws SQLException { assertThat(actual.getAutoCommit(), is(autoCommit)); - Map cachedConnections = getCachedConnections(actual); + Multimap cachedConnections = getCachedConnections(actual); assertThat(cachedConnections.size(), is(2)); for (Connection each : cachedConnections.values()) { assertThat(each.getAutoCommit(), is(autoCommit)); @@ -88,7 +88,7 @@ public void assertClose() throws SQLException { private void assertClose(final ShardingConnection actual, final boolean closed) throws SQLException { assertThat(actual.isClosed(), is(closed)); - Map cachedConnections = getCachedConnections(actual); + Multimap cachedConnections = getCachedConnections(actual); assertThat(cachedConnections.size(), is(2)); for (Connection each : cachedConnections.values()) { assertThat(each.isClosed(), is(closed)); @@ -109,7 +109,7 @@ public void assertSetReadOnly() throws SQLException { private void assertReadOnly(final ShardingConnection actual, final boolean readOnly) throws SQLException { assertThat(actual.isReadOnly(), is(readOnly)); - Map cachedConnections = getCachedConnections(actual); + Multimap cachedConnections = getCachedConnections(actual); assertThat(cachedConnections.size(), is(2)); for (Connection each : cachedConnections.values()) { assertThat(each.isReadOnly(), is(readOnly)); @@ -138,7 +138,7 @@ public void assertSetTransactionIsolation() throws SQLException { private void assertTransactionIsolation(final ShardingConnection actual, final int transactionIsolation) throws SQLException { assertThat(actual.getTransactionIsolation(), is(transactionIsolation)); - Map cachedConnections = getCachedConnections(actual); + Multimap cachedConnections = getCachedConnections(actual); assertThat(cachedConnections.size(), is(2)); for (Connection each : cachedConnections.values()) { assertThat(each.getTransactionIsolation(), is(transactionIsolation)); @@ -175,11 +175,11 @@ public void assertSetHoldability() throws SQLException { } @SuppressWarnings("unchecked") - private Map getCachedConnections(final AbstractConnectionAdapter connectionAdapter) { + private Multimap getCachedConnections(final AbstractConnectionAdapter connectionAdapter) { try { Field field = AbstractConnectionAdapter.class.getDeclaredField("cachedConnections"); field.setAccessible(true); - return (Map) field.get(connectionAdapter); + return (Multimap) field.get(connectionAdapter); } catch (final ReflectiveOperationException ex) { throw new RuntimeException(ex); } diff --git a/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/DataSourceAdapterTest.java b/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/DataSourceAdapterTest.java index 94bec19521b17..d2d98926b8a93 100644 --- a/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/DataSourceAdapterTest.java +++ b/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/DataSourceAdapterTest.java @@ -34,7 +34,6 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public final class DataSourceAdapterTest extends AbstractShardingJDBCDatabaseAndTableTest { @@ -65,7 +64,6 @@ public void assertRecordMethodInvocationSuccess() { when(list.isEmpty()).thenReturn(true); getShardingDataSource().recordMethodInvocation(List.class, "isEmpty", new Class[]{}, new Object[]{}); getShardingDataSource().replayMethodsInvocation(list); - verify(list).isEmpty(); } @Test(expected = ShardingException.class) diff --git a/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/ResultSetGetterAdapterTest.java b/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/ResultSetGetterAdapterTest.java index 8f8c7694ca263..46386b4b29e31 100644 --- a/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/ResultSetGetterAdapterTest.java +++ b/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/ResultSetGetterAdapterTest.java @@ -78,19 +78,25 @@ public void close() throws SQLException { } @Test - public void assertGetBooleanForColumnIndex() throws SQLException { + public void assertGetBooleanForColumnIndex() { for (Entry each : resultSets.entrySet()) { - if (DatabaseType.H2 == each.getKey()) { - assertTrue(each.getValue().getBoolean(1)); + try { + each.getValue().getBoolean(1); + fail("Expected an SQLException to be thrown"); + } catch (final Exception exception) { + assertFalse(exception.getMessage().isEmpty()); } } } @Test - public void assertGetBooleanForColumnLabel() throws SQLException { + public void assertGetBooleanForColumnLabel() { for (Entry each : resultSets.entrySet()) { - if (DatabaseType.H2 == each.getKey()) { + try { assertTrue(each.getValue().getBoolean(columnName)); + fail("Expected an SQLException to be thrown"); + } catch (final Exception exception) { + assertFalse(exception.getMessage().isEmpty()); } } } @@ -226,14 +232,24 @@ public void assertGetBigDecimalColumnLabelWithScale() throws SQLException { @Test public void assertGetBytesForColumnIndex() throws SQLException { for (ResultSet each : resultSets.values()) { - assertTrue(each.getBytes(1).length > 0); + try { + assertTrue(each.getBytes(1).length > 0); + fail("Expected an SQLException to be thrown"); + } catch (final Exception exception) { + assertFalse(exception.getMessage().isEmpty()); + } } } @Test public void assertGetBytesForColumnLabel() throws SQLException { for (ResultSet each : resultSets.values()) { - assertTrue(each.getBytes(columnName).length > 0); + try { + assertTrue(each.getBytes(columnName).length > 0); + fail("Expected an SQLException to be thrown"); + } catch (final Exception exception) { + assertFalse(exception.getMessage().isEmpty()); + } } } @@ -243,7 +259,7 @@ public void assertGetDateForColumnIndex() { try { each.getDate(1); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -255,7 +271,7 @@ public void assertGetDateForColumnLabel() { try { each.getDate(columnName); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -267,7 +283,7 @@ public void assertGetDateColumnIndexWithCalendar() { try { each.getDate(1, Calendar.getInstance()); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -279,7 +295,7 @@ public void assertGetDateColumnLabelWithCalendar() { try { each.getDate(columnName, Calendar.getInstance()); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -291,7 +307,7 @@ public void assertGetTimeForColumnIndex() { try { each.getTime(1); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -303,7 +319,7 @@ public void assertGetTimeForColumnLabel() { try { each.getTime(columnName); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -315,7 +331,7 @@ public void assertGetTimeColumnIndexWithCalendar() { try { each.getTime(1, Calendar.getInstance()); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -327,7 +343,7 @@ public void assertGetTimeColumnLabelWithCalendar() { try { each.getTime(columnName, Calendar.getInstance()); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -342,7 +358,7 @@ public void assertGetTimestampForColumnIndex() { continue; } fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -357,7 +373,7 @@ public void assertGetTimestampForColumnLabel() { continue; } fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -372,7 +388,7 @@ public void assertGetTimestampColumnIndexWithCalendar() { continue; } fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -387,7 +403,7 @@ public void assertGetTimestampColumnLabelWithCalendar() { continue; } fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -426,7 +442,7 @@ public void assertGetUnicodeStreamForColumnIndex() throws SQLException, IOExcept if (DatabaseType.H2 == each.getKey() || DatabaseType.SQLServer == each.getKey()) { try { each.getValue().getUnicodeStream(1).read(b); - } catch (final SQLException ignore) { + } catch (final Exception ignore) { } } else { each.getValue().getUnicodeStream(1).read(b); @@ -446,7 +462,7 @@ public void assertGetUnicodeStreamForColumnLabel() throws SQLException, IOExcept if (DatabaseType.H2 == each.getKey() || DatabaseType.SQLServer == each.getKey()) { try { each.getValue().getUnicodeStream(columnName).read(b); - } catch (final SQLException ignore) { + } catch (final Exception ignore) { } } else { each.getValue().getUnicodeStream(columnName).read(b); @@ -496,37 +512,53 @@ public void assertGetCharacterStreamForColumnLabel() throws SQLException, IOExce } @Test - public void assertGetBlobForColumnIndex() throws SQLException { + public void assertGetBlobForColumnIndex() { for (Entry each : resultSets.entrySet()) { if (DatabaseType.H2 == each.getKey()) { - assertTrue(each.getValue().getBlob(1).length() > 0); + try { + assertTrue(each.getValue().getBlob(1).length() > 0); + fail("Expected an SQLException to be thrown"); + } catch (final Exception exception) { + assertFalse(exception.getMessage().isEmpty()); + } } } } @Test - public void assertGetBlobForColumnLabel() throws SQLException { + public void assertGetBlobForColumnLabel() { for (Entry each : resultSets.entrySet()) { if (DatabaseType.H2 == each.getKey()) { - assertTrue(each.getValue().getBlob(columnName).length() > 0); + try { + assertTrue(each.getValue().getBlob(columnName).length() > 0); + fail("Expected an SQLException to be thrown"); + } catch (final Exception exception) { + assertFalse(exception.getMessage().isEmpty()); + } } } } @Test - public void assertGetClobForColumnIndex() throws SQLException { + public void assertGetClobForColumnIndex() { for (Entry each : resultSets.entrySet()) { - if (DatabaseType.H2 == each.getKey()) { + try { assertThat(each.getValue().getClob(1).getSubString(1, 2), is("10")); + fail("Expected an SQLException to be thrown"); + } catch (final Exception exception) { + assertFalse(exception.getMessage().isEmpty()); } } } @Test - public void assertGetClobForColumnLabel() throws SQLException { + public void assertGetClobForColumnLabel() { for (Entry each : resultSets.entrySet()) { - if (DatabaseType.H2 == each.getKey()) { + try { assertThat(each.getValue().getClob(columnName).getSubString(1, 2), is("10")); + fail("Expected an SQLException to be thrown"); + } catch (final Exception exception) { + assertFalse(exception.getMessage().isEmpty()); } } } @@ -536,9 +568,8 @@ public void assertGetURLForColumnIndex() { for (ResultSet each : resultSets.values()) { try { each.getURL(1); - fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -550,7 +581,7 @@ public void assertGetURLForColumnLabel() { try { each.getURL(columnName); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } @@ -566,7 +597,7 @@ public void assertGetSQLXMLForColumnIndex() throws SQLException { try { each.getValue().getSQLXML(1); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } else { @@ -585,7 +616,7 @@ public void assertGetSQLXMLForColumnLabel() throws SQLException { try { each.getValue().getSQLXML(columnName); fail("Expected an SQLException to be thrown"); - } catch (final SQLException exception) { + } catch (final Exception exception) { assertFalse(exception.getMessage().isEmpty()); } } else { diff --git a/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/StatementAdapterTest.java b/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/StatementAdapterTest.java index d297f44c7aa21..fbd74abc4045c 100644 --- a/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/StatementAdapterTest.java +++ b/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/adapter/StatementAdapterTest.java @@ -85,13 +85,13 @@ public void assertSetPoolable() throws SQLException { for (Map.Entry each : statements.entrySet()) { each.getValue().setPoolable(true); each.getValue().executeQuery(sql); - assertPoolable((ShardingStatement) each.getValue(), true, each.getKey()); + assertPoolable((ShardingStatement) each.getValue(), true); each.getValue().setPoolable(false); - assertPoolable((ShardingStatement) each.getValue(), false, each.getKey()); + assertPoolable((ShardingStatement) each.getValue(), false); } } - private void assertPoolable(final ShardingStatement actual, final boolean poolable, final DatabaseType type) throws SQLException { + private void assertPoolable(final ShardingStatement actual, final boolean poolable) throws SQLException { assertThat(actual.isPoolable(), is(poolable)); assertThat(actual.getRoutedStatements().size(), is(4)); for (Statement each : actual.getRoutedStatements()) { diff --git a/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/core/connection/ShardingConnectionTest.java b/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/core/connection/ShardingConnectionTest.java index 949d166ed74c4..16eee56f8db7a 100644 --- a/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/core/connection/ShardingConnectionTest.java +++ b/sharding-jdbc/src/test/java/io/shardingsphere/core/jdbc/core/connection/ShardingConnectionTest.java @@ -22,8 +22,8 @@ import io.shardingsphere.core.api.config.TableRuleConfiguration; import io.shardingsphere.core.constant.DatabaseType; import io.shardingsphere.core.fixture.TestDataSource; +import io.shardingsphere.core.jdbc.core.ShardingContext; import io.shardingsphere.core.jdbc.core.datasource.MasterSlaveDataSource; -import io.shardingsphere.core.jdbc.core.datasource.ShardingDataSource; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -65,16 +65,15 @@ public static void init() throws SQLException { @Before public void setUp() { + ShardingContext shardingContext = mock(ShardingContext.class); + when(shardingContext.getDatabaseType()).thenReturn(DatabaseType.H2); ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration(); TableRuleConfiguration tableRuleConfig = new TableRuleConfiguration(); tableRuleConfig.setLogicTable("test"); shardingRuleConfig.getTableRuleConfigs().add(tableRuleConfig); Map dataSourceMap = new HashMap<>(1, 1); dataSourceMap.put(DS_NAME, masterSlaveDataSource); - ShardingDataSource shardingDataSource = mock(ShardingDataSource.class); - when(shardingDataSource.getDatabaseType()).thenReturn(DatabaseType.H2); - when(shardingDataSource.getDataSourceMap()).thenReturn(dataSourceMap); - connection = new ShardingConnection(shardingDataSource); + connection = new ShardingConnection(dataSourceMap, shardingContext); } @After diff --git a/sharding-jdbc/src/test/resources/integrate/cases/dml/dml-integrate-test-cases.xml b/sharding-jdbc/src/test/resources/integrate/cases/dml/dml-integrate-test-cases.xml index d5465c7eba3fa..5ca3081fcde8c 100644 --- a/sharding-jdbc/src/test/resources/integrate/cases/dml/dml-integrate-test-cases.xml +++ b/sharding-jdbc/src/test/resources/integrate/cases/dml/dml-integrate-test-cases.xml @@ -101,6 +101,18 @@ + + + + + + + + + + + + @@ -108,7 +120,7 @@ - + @@ -116,11 +128,11 @@ - + - + diff --git a/sharding-opentracing/src/main/java/io/shardingsphere/opentracing/listener/RootInvokeEventListener.java b/sharding-opentracing/src/main/java/io/shardingsphere/opentracing/listener/RootInvokeEventListener.java index 9cc63e8f5d851..5f7593d5d84d2 100644 --- a/sharding-opentracing/src/main/java/io/shardingsphere/opentracing/listener/RootInvokeEventListener.java +++ b/sharding-opentracing/src/main/java/io/shardingsphere/opentracing/listener/RootInvokeEventListener.java @@ -22,7 +22,6 @@ import io.opentracing.ActiveSpan; import io.opentracing.tag.Tags; import io.shardingsphere.core.event.root.RootInvokeEvent; -import io.shardingsphere.core.event.root.RootInvokeStartEvent; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; import io.shardingsphere.opentracing.ShardingTags; import io.shardingsphere.opentracing.ShardingTracer; @@ -57,9 +56,7 @@ public void listen(final RootInvokeEvent event) { protected void beforeExecute(final RootInvokeEvent event) { ActiveSpan span = ShardingTracer.get().buildSpan(OPERATION_NAME).withTag(Tags.COMPONENT.getKey(), ShardingTags.COMPONENT_NAME).startActive(); ACTIVE_SPAN.set(span); - if (((RootInvokeStartEvent) event).isParallelExecute()) { - ExecutorDataMap.getDataMap().put(OVERALL_SPAN_CONTINUATION, span.capture()); - } + ExecutorDataMap.getDataMap().put(OVERALL_SPAN_CONTINUATION, span.capture()); } @Override diff --git a/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/SQLParsingEventListenerTest.java b/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/SQLParsingEventListenerTest.java index e6037dbcf41bb..caa1491e47f9c 100644 --- a/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/SQLParsingEventListenerTest.java +++ b/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/SQLParsingEventListenerTest.java @@ -21,7 +21,6 @@ import com.google.common.eventbus.EventBus; import io.opentracing.NoopTracerFactory; import io.opentracing.mock.MockTracer; -import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import io.opentracing.util.ThreadLocalActiveSpanSource; import io.shardingsphere.core.api.config.ShardingRuleConfiguration; @@ -29,10 +28,7 @@ import io.shardingsphere.core.constant.DatabaseType; import io.shardingsphere.core.event.ShardingEventBusInstance; import io.shardingsphere.core.jdbc.core.ShardingContext; -import io.shardingsphere.core.jdbc.core.connection.ShardingConnection; import io.shardingsphere.core.jdbc.core.datasource.ShardingDataSource; -import io.shardingsphere.core.jdbc.core.statement.ShardingPreparedStatement; -import io.shardingsphere.core.jdbc.core.statement.ShardingStatement; import io.shardingsphere.core.metadata.ShardingMetaData; import io.shardingsphere.core.metadata.datasource.ShardingDataSourceMetaData; import io.shardingsphere.core.metadata.table.ShardingTableMetaData; @@ -41,13 +37,10 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; -import org.junit.Test; import org.mockito.Mockito; import javax.sql.DataSource; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; @@ -55,9 +48,6 @@ import java.util.LinkedHashMap; import java.util.Map; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -114,40 +104,6 @@ private DataSource mockDataSource() throws SQLException { return result; } - @Test - public void assertPreparedStatementParsing() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - ShardingPreparedStatement statement = new ShardingPreparedStatement(new ShardingConnection(shardingDataSource), "select * from t_order"); - Method sqlRouteMethod = ShardingPreparedStatement.class.getDeclaredMethod("sqlRoute"); - sqlRouteMethod.setAccessible(true); - sqlRouteMethod.invoke(statement); - assertThat(TRACER.finishedSpans().size(), is(1)); - - } - - @Test - public void assertStatementParsing() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - ShardingStatement statement = new ShardingStatement(new ShardingConnection(shardingDataSource)); - Method sqlRouteMethod = ShardingStatement.class.getDeclaredMethod("sqlRoute", String.class); - sqlRouteMethod.setAccessible(true); - sqlRouteMethod.invoke(statement, "select * from t_order"); - assertThat(TRACER.finishedSpans().size(), is(1)); - } - - @Test - public void assertException() { - try { - ShardingStatement statement = new ShardingStatement(new ShardingConnection(shardingDataSource)); - Method sqlRouteMethod = ShardingStatement.class.getDeclaredMethod("sqlRoute", String.class); - sqlRouteMethod.setAccessible(true); - sqlRouteMethod.invoke(statement, "111"); - // CHECKSTYLE:OFF - } catch (final Exception ex) { - // CHECKSTYLE:ON - } - assertThat(TRACER.finishedSpans().size(), is(1)); - assertTrue((Boolean) TRACER.finishedSpans().get(0).tags().get(Tags.ERROR.getKey())); - } - private static void releaseTracer() throws NoSuchFieldException, IllegalAccessException { Field tracerField = GlobalTracer.class.getDeclaredField("tracer"); tracerField.setAccessible(true); diff --git a/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/listener/ExecuteEventListenerTest.java b/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/listener/ExecuteEventListenerTest.java index c67393a8b050a..c4964bbe12e2a 100644 --- a/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/listener/ExecuteEventListenerTest.java +++ b/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/listener/ExecuteEventListenerTest.java @@ -17,16 +17,15 @@ package io.shardingsphere.opentracing.listener; +import io.shardingsphere.core.constant.ConnectionMode; import io.shardingsphere.core.constant.DatabaseType; import io.shardingsphere.core.constant.SQLType; import io.shardingsphere.core.executor.ShardingExecuteEngine; -import io.shardingsphere.core.executor.batch.BatchPreparedStatementExecuteUnit; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; +import io.shardingsphere.core.executor.StatementExecuteUnit; import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; -import io.shardingsphere.core.executor.statement.StatementExecuteUnit; import io.shardingsphere.core.routing.RouteUnit; import io.shardingsphere.core.routing.SQLUnit; import org.junit.After; @@ -34,11 +33,9 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -72,12 +69,12 @@ public void assertSingleStatement() throws SQLException { SQLExecuteCallback executeCallback = new SQLExecuteCallback(DatabaseType.MySQL, SQLType.DML, isExceptionThrown, dataMap) { @Override - protected Integer executeSQL(final SQLExecuteUnit sqlExecuteUnit) { + protected Integer executeSQL(final StatementExecuteUnit statementExecuteUnit) { return 0; } }; - sqlExecuteTemplate.execute(Collections.singleton( - new StatementExecuteUnit(new RouteUnit("ds_0", new SQLUnit("insert into ...", Collections.singletonList(Collections.singletonList(1)))), statement)), executeCallback); + sqlExecuteTemplate.execute(Collections.singleton(new StatementExecuteUnit(new RouteUnit("ds_0", + new SQLUnit("insert into ...", Collections.singletonList(Collections.singletonList(1)))), statement, ConnectionMode.MEMORY_STRICTLY)), executeCallback); assertThat(getTracer().finishedSpans().size(), is(1)); } @@ -88,18 +85,20 @@ public void assertMultiStatement() throws SQLException { when(stm1.getConnection()).thenReturn(mock(Connection.class)); when(stm1.getConnection().getMetaData()).thenReturn(mock(DatabaseMetaData.class)); when(stm1.getConnection().getMetaData().getURL()).thenReturn(HOST_URL); - statementExecuteUnits.add(new StatementExecuteUnit(new RouteUnit("ds_0", new SQLUnit("insert into ...", Collections.singletonList(Collections.singletonList(1)))), stm1)); + statementExecuteUnits.add(new StatementExecuteUnit(new RouteUnit("ds_0", + new SQLUnit("insert into ...", Collections.singletonList(Collections.singletonList(1)))), stm1, ConnectionMode.MEMORY_STRICTLY)); Statement stm2 = mock(Statement.class); when(stm2.getConnection()).thenReturn(mock(Connection.class)); when(stm2.getConnection().getMetaData()).thenReturn(mock(DatabaseMetaData.class)); when(stm2.getConnection().getMetaData().getURL()).thenReturn(HOST_URL); - statementExecuteUnits.add(new StatementExecuteUnit(new RouteUnit("ds_0", new SQLUnit("insert into ...", Collections.singletonList(Collections.singletonList(1)))), stm2)); + statementExecuteUnits.add(new StatementExecuteUnit(new RouteUnit("ds_0", + new SQLUnit("insert into ...", Collections.singletonList(Collections.singletonList(1)))), stm2, ConnectionMode.MEMORY_STRICTLY)); final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); final Map dataMap = ExecutorDataMap.getDataMap(); SQLExecuteCallback executeCallback = new SQLExecuteCallback(DatabaseType.MySQL, SQLType.DML, isExceptionThrown, dataMap) { @Override - protected Integer executeSQL(final SQLExecuteUnit sqlExecuteUnit) { + protected Integer executeSQL(final StatementExecuteUnit statementExecuteUnit) { return 0; } }; @@ -107,33 +106,6 @@ protected Integer executeSQL(final SQLExecuteUnit sqlExecuteUnit) { assertThat(getTracer().finishedSpans().size(), is(2)); } - @Test - public void assertBatchPreparedStatement() throws SQLException { - final List batchPreparedStatementExecuteUnits = new ArrayList<>(2); - final List> parameterSets = Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4)); - PreparedStatement preparedStatement1 = mock(PreparedStatement.class); - when(preparedStatement1.getConnection()).thenReturn(mock(Connection.class)); - when(preparedStatement1.getConnection().getMetaData()).thenReturn(mock(DatabaseMetaData.class)); - when(preparedStatement1.getConnection().getMetaData().getURL()).thenReturn(HOST_URL); - batchPreparedStatementExecuteUnits.add(new BatchPreparedStatementExecuteUnit(new RouteUnit("ds_0", new SQLUnit("insert into ...", parameterSets)), preparedStatement1)); - PreparedStatement preparedStatement2 = mock(PreparedStatement.class); - when(preparedStatement2.getConnection()).thenReturn(mock(Connection.class)); - when(preparedStatement2.getConnection().getMetaData()).thenReturn(mock(DatabaseMetaData.class)); - when(preparedStatement2.getConnection().getMetaData().getURL()).thenReturn(HOST_URL); - batchPreparedStatementExecuteUnits.add(new BatchPreparedStatementExecuteUnit(new RouteUnit("ds_1", new SQLUnit("insert into ...", parameterSets)), preparedStatement2)); - final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); - final Map dataMap = ExecutorDataMap.getDataMap(); - SQLExecuteCallback executeCallback = new SQLExecuteCallback(DatabaseType.MySQL, SQLType.DML, isExceptionThrown, dataMap) { - - @Override - protected Integer executeSQL(final SQLExecuteUnit sqlExecuteUnit) { - return 0; - } - }; - sqlExecuteTemplate.execute(batchPreparedStatementExecuteUnits, executeCallback); - assertThat(getTracer().finishedSpans().size(), is(2)); - } - @Test(expected = SQLException.class) public void assertSQLException() throws SQLException { Statement statement = mock(Statement.class); @@ -145,11 +117,11 @@ public void assertSQLException() throws SQLException { SQLExecuteCallback executeCallback = new SQLExecuteCallback(DatabaseType.MySQL, SQLType.DQL, isExceptionThrown, dataMap) { @Override - protected Integer executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { + protected Integer executeSQL(final StatementExecuteUnit statementExecuteUnit) throws SQLException { throw new SQLException(); } }; - sqlExecuteTemplate.execute(Collections.singleton( - new StatementExecuteUnit(new RouteUnit("ds_0", new SQLUnit("select ...", Collections.singletonList(Collections.singletonList(1)))), statement)), executeCallback); + sqlExecuteTemplate.execute(Collections.singleton(new StatementExecuteUnit(new RouteUnit("ds_0", + new SQLUnit("select ...", Collections.singletonList(Collections.singletonList(1)))), statement, ConnectionMode.MEMORY_STRICTLY)), executeCallback); } } diff --git a/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/listener/ParsingEventListenerTest.java b/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/listener/ParsingEventListenerTest.java index 6db7208f9cad8..a5c67c5013367 100644 --- a/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/listener/ParsingEventListenerTest.java +++ b/sharding-opentracing/src/test/java/io/shardingsphere/opentracing/listener/ParsingEventListenerTest.java @@ -18,37 +18,28 @@ package io.shardingsphere.opentracing.listener; import io.opentracing.tag.Tags; -import io.shardingsphere.core.jdbc.core.ShardingContext; import io.shardingsphere.core.jdbc.core.connection.ShardingConnection; -import io.shardingsphere.core.jdbc.core.datasource.ShardingDataSource; import io.shardingsphere.core.jdbc.core.statement.ShardingPreparedStatement; import io.shardingsphere.core.jdbc.core.statement.ShardingStatement; import io.shardingsphere.opentracing.fixture.ShardingContextBuilder; import org.junit.Test; -import org.mockito.Mockito; +import javax.sql.DataSource; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.SQLException; +import java.util.Collections; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.when; public final class ParsingEventListenerTest extends BaseEventListenerTest { - private final ShardingDataSource shardingDataSource; - - public ParsingEventListenerTest() throws SQLException { - ShardingContext shardingContext = ShardingContextBuilder.build(); - shardingDataSource = Mockito.mock(ShardingDataSource.class); - when(shardingDataSource.getShardingContext()).thenReturn(shardingContext); - } - @Test - public void assertPreparedStatementParsing() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - ShardingPreparedStatement statement = new ShardingPreparedStatement(new ShardingConnection(shardingDataSource), "select * from t_order"); + public void assertPreparedStatementParsing() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, SQLException { + ShardingPreparedStatement statement = new ShardingPreparedStatement( + new ShardingConnection(Collections.emptyMap(), ShardingContextBuilder.build()), "select * from t_order"); Method sqlRouteMethod = ShardingPreparedStatement.class.getDeclaredMethod("sqlRoute"); sqlRouteMethod.setAccessible(true); sqlRouteMethod.invoke(statement); @@ -57,8 +48,8 @@ public void assertPreparedStatementParsing() throws NoSuchMethodException, Invoc } @Test - public void assertStatementParsing() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - ShardingStatement statement = new ShardingStatement(new ShardingConnection(shardingDataSource)); + public void assertStatementParsing() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, SQLException { + ShardingStatement statement = new ShardingStatement(new ShardingConnection(Collections.emptyMap(), ShardingContextBuilder.build())); Method sqlRouteMethod = ShardingStatement.class.getDeclaredMethod("sqlRoute", String.class); sqlRouteMethod.setAccessible(true); sqlRouteMethod.invoke(statement, "select * from t_order"); @@ -68,7 +59,7 @@ public void assertStatementParsing() throws NoSuchMethodException, InvocationTar @Test public void assertException() { try { - ShardingStatement statement = new ShardingStatement(new ShardingConnection(shardingDataSource)); + ShardingStatement statement = new ShardingStatement(new ShardingConnection(Collections.emptyMap(), ShardingContextBuilder.build())); Method sqlRouteMethod = ShardingStatement.class.getDeclaredMethod("sqlRoute", String.class); sqlRouteMethod.setAccessible(true); sqlRouteMethod.invoke(statement, "111"); diff --git a/sharding-orchestration/sharding-jdbc-orchestration/src/main/java/io/shardingsphere/jdbc/orchestration/internal/datasource/OrchestrationShardingDataSource.java b/sharding-orchestration/sharding-jdbc-orchestration/src/main/java/io/shardingsphere/jdbc/orchestration/internal/datasource/OrchestrationShardingDataSource.java index dbb34523e567b..067e73b049caa 100644 --- a/sharding-orchestration/sharding-jdbc-orchestration/src/main/java/io/shardingsphere/jdbc/orchestration/internal/datasource/OrchestrationShardingDataSource.java +++ b/sharding-orchestration/sharding-jdbc-orchestration/src/main/java/io/shardingsphere/jdbc/orchestration/internal/datasource/OrchestrationShardingDataSource.java @@ -99,7 +99,7 @@ public void renew(final ShardingConfigurationEventBusEvent shardingEvent) throws @Subscribe public void renew(final DisabledStateEventBusEvent disabledStateEventBusEvent) { Map newDataSourceMap = getAvailableDataSourceMap(disabledStateEventBusEvent.getDisabledDataSourceNames()); - dataSource = new ShardingDataSource(newDataSourceMap, dataSource.getShardingContext(), dataSource.getShardingProperties(), dataSource.getDatabaseType()); + dataSource = new ShardingDataSource(newDataSourceMap, dataSource.getShardingContext(), dataSource.getShardingProperties()); } } diff --git a/sharding-orchestration/sharding-orchestration-reg/src/test/java/io/shardingsphere/orchestration/reg/newzk/client/cache/PathTreeTest.java b/sharding-orchestration/sharding-orchestration-reg/src/test/java/io/shardingsphere/orchestration/reg/newzk/client/cache/PathTreeTest.java index e528c26830ff4..c5124baa5534e 100644 --- a/sharding-orchestration/sharding-orchestration-reg/src/test/java/io/shardingsphere/orchestration/reg/newzk/client/cache/PathTreeTest.java +++ b/sharding-orchestration/sharding-orchestration-reg/src/test/java/io/shardingsphere/orchestration/reg/newzk/client/cache/PathTreeTest.java @@ -105,7 +105,7 @@ public void assertGetChildren() throws KeeperException, InterruptedException { } @Test - public void assertPut() throws KeeperException, InterruptedException { + public void assertPut() { final String key = "a/b/bb"; final String value = "bbb11"; pathTree.put(key, value); @@ -187,7 +187,7 @@ public void assertRefreshPeriodic() throws KeeperException, InterruptedException } @Test - public void assertStopRefresh() throws KeeperException, InterruptedException { + public void assertStopRefresh() { try { pathTree.refreshPeriodic(1); sleep(100); diff --git a/sharding-proxy/pom.xml b/sharding-proxy/pom.xml index 0bb04a7a001a1..dcaa3e08c760e 100644 --- a/sharding-proxy/pom.xml +++ b/sharding-proxy/pom.xml @@ -27,7 +27,11 @@ sharding-transaction ${project.version} - + + io.shardingsphere + sharding-opentracing + ${project.version} + com.google.guava guava @@ -45,7 +49,6 @@ org.slf4j slf4j-api - ch.qos.logback logback-classic @@ -60,7 +63,6 @@ org.projectlombok lombok - junit junit @@ -77,6 +79,16 @@ commons-codec commons-codec + + org.apache.skywalking + apm-toolkit-opentracing + 5.0.0-RC2 + + + org.apache.skywalking + apm-collector-core + 5.0.0-RC2 + diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/Bootstrap.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/Bootstrap.java index 24873f823fac8..04aff50b1b3cf 100644 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/Bootstrap.java +++ b/sharding-proxy/src/main/java/io/shardingsphere/proxy/Bootstrap.java @@ -21,6 +21,7 @@ import io.shardingsphere.core.yaml.YamlRuleConfiguration; import io.shardingsphere.core.yaml.other.YamlServerConfiguration; import io.shardingsphere.jdbc.orchestration.internal.OrchestrationFacade; +import io.shardingsphere.opentracing.ShardingTracer; import io.shardingsphere.proxy.config.ProxyContext; import io.shardingsphere.proxy.config.yaml.ProxyConfiguration; import io.shardingsphere.proxy.config.yaml.ProxyYamlConfigurationLoader; @@ -30,6 +31,7 @@ import io.shardingsphere.proxy.listener.ProxyListenerRegister; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer; import java.io.IOException; import java.util.HashMap; @@ -56,6 +58,7 @@ public final class Bootstrap { * @throws IOException IO exception */ public static void main(final String[] args) throws InterruptedException, IOException { + ShardingTracer.init(new SkywalkingTracer()); ProxyConfiguration proxyConfig = new ProxyYamlConfigurationLoader().load(); int port = getPort(args); new ProxyListenerRegister().register(); diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/BackendHandlerFactory.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/BackendHandlerFactory.java index eccbfb7d69290..7ff060acf11bf 100644 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/BackendHandlerFactory.java +++ b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/BackendHandlerFactory.java @@ -20,9 +20,12 @@ import io.shardingsphere.core.constant.DatabaseType; import io.shardingsphere.proxy.backend.jdbc.JDBCBackendHandler; import io.shardingsphere.proxy.backend.jdbc.connection.BackendConnection; -import io.shardingsphere.proxy.backend.jdbc.execute.JDBCExecuteEngineFactory; +import io.shardingsphere.proxy.backend.jdbc.execute.JDBCExecuteEngine; +import io.shardingsphere.proxy.backend.jdbc.wrapper.PreparedStatementExecutorWrapper; +import io.shardingsphere.proxy.backend.jdbc.wrapper.StatementExecutorWrapper; import io.shardingsphere.proxy.backend.netty.NettyBackendHandler; import io.shardingsphere.proxy.config.ProxyContext; +import io.shardingsphere.proxy.config.RuleRegistry; import io.shardingsphere.proxy.frontend.common.FrontendHandler; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -33,6 +36,7 @@ * Backend handler factory. * * @author zhangliang + * @author panjuan */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class BackendHandlerFactory { @@ -52,10 +56,11 @@ public final class BackendHandlerFactory { */ public static BackendHandler newTextProtocolInstance( final int connectionId, final int sequenceId, final String sql, final BackendConnection backendConnection, final DatabaseType databaseType, final FrontendHandler frontendHandler) { + RuleRegistry ruleRegistry = PROXY_CONTEXT.getRuleRegistry(frontendHandler.getCurrentSchema()); return PROXY_CONTEXT.isUseNIO() - ? new NettyBackendHandler(frontendHandler, PROXY_CONTEXT.getRuleRegistry(frontendHandler.getCurrentSchema()), connectionId, sequenceId, sql, databaseType) + ? new NettyBackendHandler(frontendHandler, ruleRegistry, connectionId, sequenceId, sql, databaseType) : new JDBCBackendHandler( - frontendHandler, PROXY_CONTEXT.getRuleRegistry(frontendHandler.getCurrentSchema()), sql, JDBCExecuteEngineFactory.createTextProtocolInstance(backendConnection)); + frontendHandler, ruleRegistry, sql, new JDBCExecuteEngine(backendConnection, new StatementExecutorWrapper(ruleRegistry))); } /** @@ -73,8 +78,9 @@ public static BackendHandler newTextProtocolInstance( public static BackendHandler newBinaryProtocolInstance( final int connectionId, final int sequenceId, final String sql, final List parameters, final BackendConnection backendConnection, final DatabaseType databaseType, final FrontendHandler frontendHandler) { - return PROXY_CONTEXT.isUseNIO() ? new NettyBackendHandler(frontendHandler, PROXY_CONTEXT.getRuleRegistry(frontendHandler.getCurrentSchema()), connectionId, sequenceId, sql, databaseType) - : new JDBCBackendHandler(frontendHandler, PROXY_CONTEXT.getRuleRegistry(frontendHandler.getCurrentSchema()), sql, - JDBCExecuteEngineFactory.createBinaryProtocolInstance(parameters, backendConnection)); + RuleRegistry ruleRegistry = PROXY_CONTEXT.getRuleRegistry(frontendHandler.getCurrentSchema()); + return PROXY_CONTEXT.isUseNIO() ? new NettyBackendHandler(frontendHandler, ruleRegistry, connectionId, sequenceId, sql, databaseType) + : new JDBCBackendHandler(frontendHandler, ruleRegistry, sql, new JDBCExecuteEngine(backendConnection, new PreparedStatementExecutorWrapper(ruleRegistry, parameters))); } } + diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/connection/BackendConnection.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/connection/BackendConnection.java index 8fcab268ee070..20d267cd3c664 100644 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/connection/BackendConnection.java +++ b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/connection/BackendConnection.java @@ -17,6 +17,15 @@ package io.shardingsphere.proxy.backend.jdbc.connection; +import io.shardingsphere.core.constant.DatabaseType; +import io.shardingsphere.core.event.ShardingEventBusInstance; +import io.shardingsphere.core.event.connection.CloseConnectionEvent; +import io.shardingsphere.core.event.connection.CloseConnectionFinishEvent; +import io.shardingsphere.core.event.connection.CloseConnectionStartEvent; +import io.shardingsphere.core.event.connection.GetConnectionEvent; +import io.shardingsphere.core.event.connection.GetConnectionFinishEvent; +import io.shardingsphere.core.event.connection.GetConnectionStartEvent; +import io.shardingsphere.core.metadata.datasource.DataSourceMetaDataFactory; import io.shardingsphere.core.routing.router.masterslave.MasterVisitedManager; import io.shardingsphere.proxy.config.RuleRegistry; import lombok.Getter; @@ -28,6 +37,7 @@ import java.sql.Statement; import java.util.Collection; import java.util.LinkedList; +import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -49,16 +59,30 @@ public final class BackendConnection implements AutoCloseable { private final Collection cachedResultSets = new CopyOnWriteArrayList<>(); /** - * Get connection of current thread datasource. + * Get connections of current thread datasource. * * @param dataSourceName data source name + * @param connectionSize size of connections to be get * @return connection * @throws SQLException SQL exception */ - public Connection getConnection(final String dataSourceName) throws SQLException { - Connection result = ruleRegistry.getBackendDataSource().getConnection(dataSourceName); - cachedConnections.add(result); - return result; + public List getConnections(final String dataSourceName, final int connectionSize) throws SQLException { + try { + ShardingEventBusInstance.getInstance().post(new GetConnectionStartEvent(dataSourceName)); + List result = ruleRegistry.getBackendDataSource().getConnections(dataSourceName, connectionSize); + cachedConnections.addAll(result); + GetConnectionEvent finishEvent = new GetConnectionFinishEvent(DataSourceMetaDataFactory.newInstance(DatabaseType.MySQL, result.get(0).getMetaData().getURL())); + finishEvent.setExecuteSuccess(); + ShardingEventBusInstance.getInstance().post(finishEvent); + return result; + // CHECKSTYLE:OFF + } catch (final Exception ex) { + // CHECKSTYLE:ON + GetConnectionEvent finishEvent = new GetConnectionFinishEvent(null); + finishEvent.setExecuteFailure(ex); + ShardingEventBusInstance.getInstance().post(finishEvent); + throw ex; + } } /** @@ -127,11 +151,17 @@ private Collection closeStatements() { private Collection closeConnections() { Collection result = new LinkedList<>(); + CloseConnectionEvent finishEvent = new CloseConnectionFinishEvent(); for (Connection each : cachedConnections) { try { + ShardingEventBusInstance.getInstance().post(new CloseConnectionStartEvent(each.getCatalog(), DataSourceMetaDataFactory.newInstance(DatabaseType.MySQL, each.getMetaData().getURL()))); each.close(); + finishEvent.setExecuteSuccess(); + ShardingEventBusInstance.getInstance().post(finishEvent); } catch (SQLException ex) { + finishEvent.setExecuteFailure(ex); result.add(ex); + ShardingEventBusInstance.getInstance().post(finishEvent); } } return result; diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/datasource/JDBCBackendDataSource.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/datasource/JDBCBackendDataSource.java index 6a381902ee6cd..90713029a915b 100644 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/datasource/JDBCBackendDataSource.java +++ b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/datasource/JDBCBackendDataSource.java @@ -30,7 +30,9 @@ import java.lang.reflect.Method; import java.sql.Connection; import java.sql.SQLException; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -91,7 +93,27 @@ private JDBCBackendDataSourceFactory getBackendDataSourceFactory(final Transacti * @throws SQLException SQL exception */ public Connection getConnection(final String dataSourceName) throws SQLException { - return getDataSourceMap().get(dataSourceName).getConnection(); + return getConnections(dataSourceName, 1).get(0); + } + + /** + * Get connections. + * + * @param dataSourceName data source name + * @param connectionSize size of connections to be get + * @return connections + * @throws SQLException SQL exception + */ + @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") + public List getConnections(final String dataSourceName, final int connectionSize) throws SQLException { + List result = new ArrayList<>(connectionSize); + DataSource dataSource = getDataSourceMap().get(dataSourceName); + synchronized (dataSource) { + for (int i = 0; i < connectionSize; i++) { + result.add(dataSource.getConnection()); + } + } + return result; } private Map getDataSourceMap() { diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/JDBCExecuteEngine.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/JDBCExecuteEngine.java index 419e6fa14b11b..ecb6206a86d4d 100644 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/JDBCExecuteEngine.java +++ b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/JDBCExecuteEngine.java @@ -17,13 +17,34 @@ package io.shardingsphere.proxy.backend.jdbc.execute; +import io.shardingsphere.core.constant.ConnectionMode; +import io.shardingsphere.core.constant.DatabaseType; +import io.shardingsphere.core.constant.SQLType; +import io.shardingsphere.core.executor.ShardingExecuteGroup; +import io.shardingsphere.core.executor.StatementExecuteUnit; +import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; +import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; +import io.shardingsphere.core.executor.sql.execute.result.MemoryQueryResult; +import io.shardingsphere.core.executor.sql.execute.result.StreamQueryResult; +import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; +import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; +import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareCallback; +import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareTemplate; import io.shardingsphere.core.merger.QueryResult; +import io.shardingsphere.core.parsing.parser.sql.dml.insert.InsertStatement; +import io.shardingsphere.core.routing.RouteUnit; +import io.shardingsphere.core.routing.SQLRouteResult; +import io.shardingsphere.proxy.backend.BackendExecutorContext; import io.shardingsphere.proxy.backend.SQLExecuteEngine; import io.shardingsphere.proxy.backend.jdbc.connection.BackendConnection; +import io.shardingsphere.proxy.backend.jdbc.execute.response.ExecuteQueryResponse; +import io.shardingsphere.proxy.backend.jdbc.execute.response.ExecuteResponse; +import io.shardingsphere.proxy.backend.jdbc.execute.response.ExecuteUpdateResponse; import io.shardingsphere.proxy.backend.jdbc.execute.response.unit.ExecuteQueryResponseUnit; import io.shardingsphere.proxy.backend.jdbc.execute.response.unit.ExecuteResponseUnit; import io.shardingsphere.proxy.backend.jdbc.execute.response.unit.ExecuteUpdateResponseUnit; import io.shardingsphere.proxy.backend.jdbc.wrapper.JDBCExecutorWrapper; +import io.shardingsphere.proxy.config.ProxyContext; import io.shardingsphere.proxy.transport.mysql.constant.ColumnType; import io.shardingsphere.proxy.transport.mysql.packet.command.query.ColumnDefinition41Packet; import io.shardingsphere.proxy.transport.mysql.packet.command.query.FieldCountPacket; @@ -34,6 +55,7 @@ import lombok.RequiredArgsConstructor; import lombok.Setter; +import java.sql.Connection; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; @@ -41,17 +63,21 @@ import java.util.Collection; import java.util.LinkedList; import java.util.List; +import java.util.Map; /** * SQL Execute engine for JDBC. * * @author zhaojun * @author zhangliang + * @author panjuan */ +@RequiredArgsConstructor @Getter @Setter -@RequiredArgsConstructor -public abstract class JDBCExecuteEngine implements SQLExecuteEngine { +public final class JDBCExecuteEngine implements SQLExecuteEngine { + + private static final Integer MEMORY_FETCH_ONE_ROW_A_TIME = Integer.MIN_VALUE; private final List queryResults = new LinkedList<>(); @@ -63,7 +89,43 @@ public abstract class JDBCExecuteEngine implements SQLExecuteEngine { private List columnTypes; - protected final ExecuteResponseUnit executeWithMetadata(final Statement statement, final String sql, final boolean isReturnGeneratedKeys) throws SQLException { + private final SQLExecutePrepareTemplate sqlExecutePrepareTemplate; + + private final SQLExecuteTemplate sqlExecuteTemplate; + + public JDBCExecuteEngine(final BackendConnection backendConnection, final JDBCExecutorWrapper jdbcExecutorWrapper) { + this.backendConnection = backendConnection; + this.jdbcExecutorWrapper = jdbcExecutorWrapper; + sqlExecutePrepareTemplate = new SQLExecutePrepareTemplate(ProxyContext.getInstance().getMaxConnectionsSizePerQuery()); + sqlExecuteTemplate = new SQLExecuteTemplate(BackendExecutorContext.getInstance().getExecuteEngine()); + } + + @SuppressWarnings("unchecked") + @Override + public ExecuteResponse execute(final SQLRouteResult routeResult) throws SQLException { + boolean isReturnGeneratedKeys = routeResult.getSqlStatement() instanceof InsertStatement; + SQLType sqlType = routeResult.getSqlStatement().getType(); + boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); + Map dataMap = ExecutorDataMap.getDataMap(); + Collection> sqlExecuteGroups = + sqlExecutePrepareTemplate.getExecuteUnitGroups(routeResult.getRouteUnits(), new ConnectionStrictlySQLExecutePrepareCallback(isReturnGeneratedKeys)); + Collection executeResponseUnits = sqlExecuteTemplate.executeGroup((Collection) sqlExecuteGroups, + new FirstConnectionStrictlySQLExecuteCallback(sqlType, isExceptionThrown, dataMap, isReturnGeneratedKeys), + new ConnectionStrictlySQLExecuteCallback(sqlType, isExceptionThrown, dataMap, isReturnGeneratedKeys)); + ExecuteResponseUnit firstExecuteResponseUnit = executeResponseUnits.iterator().next(); + return firstExecuteResponseUnit instanceof ExecuteQueryResponseUnit + ? getExecuteQueryResponse(((ExecuteQueryResponseUnit) firstExecuteResponseUnit).getQueryResponsePackets(), executeResponseUnits) : new ExecuteUpdateResponse(executeResponseUnits); + } + + private ExecuteResponse getExecuteQueryResponse(final QueryResponsePackets queryResponsePackets, final Collection executeResponseUnits) { + ExecuteQueryResponse result = new ExecuteQueryResponse(queryResponsePackets); + for (ExecuteResponseUnit each : executeResponseUnits) { + result.getQueryResults().add(((ExecuteQueryResponseUnit) each).getQueryResult()); + } + return result; + } + + private ExecuteResponseUnit executeWithMetadata(final Statement statement, final String sql, final ConnectionMode connectionMode, final boolean isReturnGeneratedKeys) throws SQLException { backendConnection.add(statement); if (!jdbcExecutorWrapper.executeSQL(statement, sql, isReturnGeneratedKeys)) { return new ExecuteUpdateResponseUnit(new OKPacket(1, statement.getUpdateCount(), isReturnGeneratedKeys ? getGeneratedKey(statement) : 0)); @@ -74,17 +136,17 @@ protected final ExecuteResponseUnit executeWithMetadata(final Statement statemen if (0 == resultSetMetaData.getColumnCount()) { return new ExecuteUpdateResponseUnit(new OKPacket(1)); } - return new ExecuteQueryResponseUnit(getHeaderPackets(resultSetMetaData), createQueryResult(resultSet)); + return new ExecuteQueryResponseUnit(getHeaderPackets(resultSetMetaData), createQueryResult(resultSet, connectionMode)); } - protected final ExecuteResponseUnit executeWithoutMetadata(final Statement statement, final String sql, final boolean isReturnGeneratedKeys) throws SQLException { + private ExecuteResponseUnit executeWithoutMetadata(final Statement statement, final String sql, final ConnectionMode connectionMode, final boolean isReturnGeneratedKeys) throws SQLException { backendConnection.add(statement); if (!jdbcExecutorWrapper.executeSQL(statement, sql, isReturnGeneratedKeys)) { return new ExecuteUpdateResponseUnit(new OKPacket(1, statement.getUpdateCount(), isReturnGeneratedKeys ? getGeneratedKey(statement) : 0)); } ResultSet resultSet = statement.getResultSet(); backendConnection.add(resultSet); - return new ExecuteQueryResponseUnit(null, createQueryResult(resultSet)); + return new ExecuteQueryResponseUnit(null, createQueryResult(resultSet, connectionMode)); } private long getGeneratedKey(final Statement statement) throws SQLException { @@ -103,5 +165,67 @@ private QueryResponsePackets getHeaderPackets(final ResultSetMetaData resultSetM return new QueryResponsePackets(fieldCountPacket, columnDefinition41Packets, new EofPacket(++currentSequenceId)); } - protected abstract QueryResult createQueryResult(ResultSet resultSet) throws SQLException; + private QueryResult createQueryResult(final ResultSet resultSet, final ConnectionMode connectionMode) throws SQLException { + return connectionMode == ConnectionMode.MEMORY_STRICTLY ? new StreamQueryResult(resultSet) : new MemoryQueryResult(resultSet); + } + + @RequiredArgsConstructor + private final class ConnectionStrictlySQLExecutePrepareCallback implements SQLExecutePrepareCallback { + + private final boolean isReturnGeneratedKeys; + + @Override + public List getConnections(final String dataSourceName, final int connectionSize) throws SQLException { + return getBackendConnection().getConnections(dataSourceName, connectionSize); + } + + @Override + public StatementExecuteUnit createStatementExecuteUnit(final Connection connection, final RouteUnit routeUnit, final ConnectionMode connectionMode) throws SQLException { + Statement statement = getJdbcExecutorWrapper().createStatement(connection, routeUnit.getSqlUnit().getSql(), isReturnGeneratedKeys); + if (connectionMode.equals(ConnectionMode.MEMORY_STRICTLY)) { + statement.setFetchSize(MEMORY_FETCH_ONE_ROW_A_TIME); + } + return new StatementExecuteUnit(routeUnit, statement, connectionMode); + } + } + + private final class FirstConnectionStrictlySQLExecuteCallback extends SQLExecuteCallback { + + private final boolean isReturnGeneratedKeys; + + private boolean hasMetaData; + + private FirstConnectionStrictlySQLExecuteCallback(final SQLType sqlType, final boolean isExceptionThrown, final Map dataMap, final boolean isReturnGeneratedKeys) { + super(DatabaseType.MySQL, sqlType, isExceptionThrown, dataMap); + this.isReturnGeneratedKeys = isReturnGeneratedKeys; + } + + @Override + public ExecuteResponseUnit executeSQL(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + if (hasMetaData) { + return executeWithoutMetadata( + statementExecuteUnit.getStatement(), statementExecuteUnit.getRouteUnit().getSqlUnit().getSql(), statementExecuteUnit.getConnectionMode(), isReturnGeneratedKeys); + } else { + hasMetaData = true; + return executeWithMetadata( + statementExecuteUnit.getStatement(), statementExecuteUnit.getRouteUnit().getSqlUnit().getSql(), statementExecuteUnit.getConnectionMode(), isReturnGeneratedKeys); + } + } + } + + private final class ConnectionStrictlySQLExecuteCallback extends SQLExecuteCallback { + + private final boolean isReturnGeneratedKeys; + + private ConnectionStrictlySQLExecuteCallback(final SQLType sqlType, final boolean isExceptionThrown, final Map dataMap, final boolean isReturnGeneratedKeys) { + super(DatabaseType.MySQL, sqlType, isExceptionThrown, dataMap); + this.isReturnGeneratedKeys = isReturnGeneratedKeys; + } + + @Override + public ExecuteResponseUnit executeSQL(final StatementExecuteUnit statementExecuteUnit) throws SQLException { + return executeWithoutMetadata( + statementExecuteUnit.getStatement(), statementExecuteUnit.getRouteUnit().getSqlUnit().getSql(), statementExecuteUnit.getConnectionMode(), isReturnGeneratedKeys); + } + } } diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/JDBCExecuteEngineFactory.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/JDBCExecuteEngineFactory.java deleted file mode 100644 index 48bd701a0ddc6..0000000000000 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/JDBCExecuteEngineFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.proxy.backend.jdbc.execute; - -import io.shardingsphere.core.constant.ConnectionMode; -import io.shardingsphere.proxy.backend.jdbc.connection.BackendConnection; -import io.shardingsphere.proxy.backend.jdbc.execute.memory.ConnectionStrictlyExecuteEngine; -import io.shardingsphere.proxy.backend.jdbc.execute.stream.MemoryStrictlyExecuteEngine; -import io.shardingsphere.proxy.backend.jdbc.wrapper.JDBCExecutorWrapper; -import io.shardingsphere.proxy.backend.jdbc.wrapper.PreparedStatementExecutorWrapper; -import io.shardingsphere.proxy.backend.jdbc.wrapper.StatementExecutorWrapper; -import io.shardingsphere.proxy.config.ProxyContext; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -import java.util.List; - -/** - * JDBC execute engine factory. - * - * @author zhangliang - */ -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public final class JDBCExecuteEngineFactory { - - private static final ProxyContext PROXY_CONTEXT = ProxyContext.getInstance(); - - /** - * Create instance for text protocol. - * - * @param backendConnection backend connection - * @return instance for text protocol - */ - public static JDBCExecuteEngine createTextProtocolInstance(final BackendConnection backendConnection) { - JDBCExecutorWrapper jdbcExecutorWrapper = new StatementExecutorWrapper(backendConnection.getRuleRegistry()); - return ConnectionMode.MEMORY_STRICTLY == PROXY_CONTEXT.getConnectionMode() - ? new MemoryStrictlyExecuteEngine(backendConnection, jdbcExecutorWrapper) : new ConnectionStrictlyExecuteEngine(backendConnection, jdbcExecutorWrapper); - } - - /** - * Create instance for binary protocol. - * - * @param parameters parameters of prepared statement - * @param backendConnection backend connection - * @return instance for binary protocol - */ - public static JDBCExecuteEngine createBinaryProtocolInstance(final List parameters, final BackendConnection backendConnection) { - JDBCExecutorWrapper jdbcExecutorWrapper = new PreparedStatementExecutorWrapper(backendConnection.getRuleRegistry(), parameters); - return ConnectionMode.MEMORY_STRICTLY == PROXY_CONTEXT.getConnectionMode() - ? new MemoryStrictlyExecuteEngine(backendConnection, jdbcExecutorWrapper) : new ConnectionStrictlyExecuteEngine(backendConnection, jdbcExecutorWrapper); - } -} diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/StatementExecuteUnit.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/StatementExecuteUnit.java deleted file mode 100644 index 3dff8e52d7dae..0000000000000 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/StatementExecuteUnit.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.proxy.backend.jdbc.execute; - -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; -import io.shardingsphere.core.routing.RouteUnit; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.sql.Statement; - -/** - * Execute unit for JDBC statement. - * - * @author zhangliang - */ -@RequiredArgsConstructor -@Getter -public final class StatementExecuteUnit implements SQLExecuteUnit { - - private final RouteUnit routeUnit; - - private final Statement statement; -} diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/memory/ConnectionStrictlyExecuteEngine.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/memory/ConnectionStrictlyExecuteEngine.java deleted file mode 100644 index 660ec897b577f..0000000000000 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/memory/ConnectionStrictlyExecuteEngine.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.proxy.backend.jdbc.execute.memory; - -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.ShardingExecuteGroup; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; -import io.shardingsphere.core.executor.sql.execute.result.MemoryQueryResult; -import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; -import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; -import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareCallback; -import io.shardingsphere.core.executor.sql.prepare.SQLExecutePrepareTemplate; -import io.shardingsphere.core.merger.QueryResult; -import io.shardingsphere.core.parsing.parser.sql.dml.insert.InsertStatement; -import io.shardingsphere.core.routing.RouteUnit; -import io.shardingsphere.core.routing.SQLRouteResult; -import io.shardingsphere.proxy.backend.BackendExecutorContext; -import io.shardingsphere.proxy.backend.jdbc.connection.BackendConnection; -import io.shardingsphere.proxy.backend.jdbc.execute.JDBCExecuteEngine; -import io.shardingsphere.proxy.backend.jdbc.execute.StatementExecuteUnit; -import io.shardingsphere.proxy.backend.jdbc.execute.response.ExecuteQueryResponse; -import io.shardingsphere.proxy.backend.jdbc.execute.response.ExecuteResponse; -import io.shardingsphere.proxy.backend.jdbc.execute.response.ExecuteUpdateResponse; -import io.shardingsphere.proxy.backend.jdbc.execute.response.unit.ExecuteQueryResponseUnit; -import io.shardingsphere.proxy.backend.jdbc.execute.response.unit.ExecuteResponseUnit; -import io.shardingsphere.proxy.backend.jdbc.wrapper.JDBCExecutorWrapper; -import io.shardingsphere.proxy.config.ProxyContext; -import io.shardingsphere.proxy.transport.mysql.packet.command.query.QueryResponsePackets; -import lombok.RequiredArgsConstructor; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Collection; -import java.util.Map; - -/** - * Connection strictly execute engine. - * - * @author zhaojun - * @author zhangliang - */ -public final class ConnectionStrictlyExecuteEngine extends JDBCExecuteEngine { - - private final SQLExecutePrepareTemplate sqlExecutePrepareTemplate; - - private final SQLExecuteTemplate sqlExecuteTemplate; - - public ConnectionStrictlyExecuteEngine(final BackendConnection backendConnection, final JDBCExecutorWrapper jdbcExecutorWrapper) { - super(backendConnection, jdbcExecutorWrapper); - sqlExecutePrepareTemplate = new SQLExecutePrepareTemplate(ProxyContext.getInstance().getMaxConnectionsSizePerQuery()); - sqlExecuteTemplate = new SQLExecuteTemplate(BackendExecutorContext.getInstance().getExecuteEngine()); - } - - @SuppressWarnings("unchecked") - @Override - public ExecuteResponse execute(final SQLRouteResult routeResult) throws SQLException { - boolean isReturnGeneratedKeys = routeResult.getSqlStatement() instanceof InsertStatement; - SQLType sqlType = routeResult.getSqlStatement().getType(); - boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); - Map dataMap = ExecutorDataMap.getDataMap(); - Collection> sqlExecuteGroups = - sqlExecutePrepareTemplate.getExecuteUnitGroups(routeResult.getRouteUnits(), new ConnectionStrictlySQLExecutePrepareCallback(isReturnGeneratedKeys)); - Collection executeResponseUnits = sqlExecuteTemplate.executeGroup((Collection) sqlExecuteGroups, - new FirstConnectionStrictlySQLExecuteCallback(sqlType, isExceptionThrown, dataMap, isReturnGeneratedKeys), - new ConnectionStrictlySQLExecuteCallback(sqlType, isExceptionThrown, dataMap, isReturnGeneratedKeys)); - ExecuteResponseUnit firstExecuteResponseUnit = executeResponseUnits.iterator().next(); - return firstExecuteResponseUnit instanceof ExecuteQueryResponseUnit - ? getExecuteQueryResponse(((ExecuteQueryResponseUnit) firstExecuteResponseUnit).getQueryResponsePackets(), executeResponseUnits) : new ExecuteUpdateResponse(executeResponseUnits); - } - - private ExecuteResponse getExecuteQueryResponse(final QueryResponsePackets queryResponsePackets, final Collection executeResponseUnits) { - ExecuteQueryResponse result = new ExecuteQueryResponse(queryResponsePackets); - for (ExecuteResponseUnit each : executeResponseUnits) { - result.getQueryResults().add(((ExecuteQueryResponseUnit) each).getQueryResult()); - } - return result; - } - - @Override - protected QueryResult createQueryResult(final ResultSet resultSet) throws SQLException { - return new MemoryQueryResult(resultSet); - } - - @RequiredArgsConstructor - private final class ConnectionStrictlySQLExecutePrepareCallback implements SQLExecutePrepareCallback { - - private final boolean isReturnGeneratedKeys; - - @Override - public Connection getConnection(final String dataSourceName) throws SQLException { - return getBackendConnection().getConnection(dataSourceName); - } - - @Override - public SQLExecuteUnit createSQLExecuteUnit(final Connection connection, final RouteUnit routeUnit) throws SQLException { - return new StatementExecuteUnit(routeUnit, getJdbcExecutorWrapper().createStatement(connection, routeUnit.getSqlUnit().getSql(), isReturnGeneratedKeys)); - } - } - - private final class FirstConnectionStrictlySQLExecuteCallback extends SQLExecuteCallback { - - private final boolean isReturnGeneratedKeys; - - private boolean hasMetaData; - - private FirstConnectionStrictlySQLExecuteCallback(final SQLType sqlType, final boolean isExceptionThrown, final Map dataMap, final boolean isReturnGeneratedKeys) { - super(DatabaseType.MySQL, sqlType, isExceptionThrown, dataMap); - this.isReturnGeneratedKeys = isReturnGeneratedKeys; - } - - @Override - public ExecuteResponseUnit executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - if (hasMetaData) { - return executeWithoutMetadata(sqlExecuteUnit.getStatement(), sqlExecuteUnit.getRouteUnit().getSqlUnit().getSql(), isReturnGeneratedKeys); - } else { - hasMetaData = true; - return executeWithMetadata(sqlExecuteUnit.getStatement(), sqlExecuteUnit.getRouteUnit().getSqlUnit().getSql(), isReturnGeneratedKeys); - } - } - } - - private final class ConnectionStrictlySQLExecuteCallback extends SQLExecuteCallback { - - private final boolean isReturnGeneratedKeys; - - private ConnectionStrictlySQLExecuteCallback(final SQLType sqlType, final boolean isExceptionThrown, final Map dataMap, final boolean isReturnGeneratedKeys) { - super(DatabaseType.MySQL, sqlType, isExceptionThrown, dataMap); - this.isReturnGeneratedKeys = isReturnGeneratedKeys; - } - - @Override - public ExecuteResponseUnit executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - return executeWithoutMetadata(sqlExecuteUnit.getStatement(), sqlExecuteUnit.getRouteUnit().getSqlUnit().getSql(), isReturnGeneratedKeys); - } - } -} diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/stream/MemoryStrictlyExecuteEngine.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/stream/MemoryStrictlyExecuteEngine.java deleted file mode 100644 index 503b4b3e1396c..0000000000000 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/backend/jdbc/execute/stream/MemoryStrictlyExecuteEngine.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2016-2018 shardingsphere.io. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- */ - -package io.shardingsphere.proxy.backend.jdbc.execute.stream; - -import io.shardingsphere.core.constant.DatabaseType; -import io.shardingsphere.core.constant.SQLType; -import io.shardingsphere.core.executor.sql.SQLExecuteUnit; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteCallback; -import io.shardingsphere.core.executor.sql.execute.SQLExecuteTemplate; -import io.shardingsphere.core.executor.sql.execute.result.StreamQueryResult; -import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorDataMap; -import io.shardingsphere.core.executor.sql.execute.threadlocal.ExecutorExceptionHandler; -import io.shardingsphere.core.merger.QueryResult; -import io.shardingsphere.core.parsing.parser.sql.dml.insert.InsertStatement; -import io.shardingsphere.core.routing.RouteUnit; -import io.shardingsphere.core.routing.SQLRouteResult; -import io.shardingsphere.proxy.backend.BackendExecutorContext; -import io.shardingsphere.proxy.backend.jdbc.connection.BackendConnection; -import io.shardingsphere.proxy.backend.jdbc.execute.JDBCExecuteEngine; -import io.shardingsphere.proxy.backend.jdbc.execute.StatementExecuteUnit; -import io.shardingsphere.proxy.backend.jdbc.execute.response.ExecuteQueryResponse; -import io.shardingsphere.proxy.backend.jdbc.execute.response.ExecuteResponse; -import io.shardingsphere.proxy.backend.jdbc.execute.response.ExecuteUpdateResponse; -import io.shardingsphere.proxy.backend.jdbc.execute.response.unit.ExecuteQueryResponseUnit; -import io.shardingsphere.proxy.backend.jdbc.execute.response.unit.ExecuteResponseUnit; -import io.shardingsphere.proxy.backend.jdbc.wrapper.JDBCExecutorWrapper; -import io.shardingsphere.proxy.transport.mysql.packet.command.query.QueryResponsePackets; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -/** - * Memory strictly execute engine. - * - * @author zhaojun - * @author zhangliang - */ -public final class MemoryStrictlyExecuteEngine extends JDBCExecuteEngine { - - private static final Integer FETCH_ONE_ROW_A_TIME = Integer.MIN_VALUE; - - private final SQLExecuteTemplate sqlExecuteTemplate; - - public MemoryStrictlyExecuteEngine(final BackendConnection backendConnection, final JDBCExecutorWrapper jdbcExecutorWrapper) { - super(backendConnection, jdbcExecutorWrapper); - sqlExecuteTemplate = new SQLExecuteTemplate(BackendExecutorContext.getInstance().getExecuteEngine()); - } - - @Override - public ExecuteResponse execute(final SQLRouteResult routeResult) throws SQLException { - boolean isReturnGeneratedKeys = routeResult.getSqlStatement() instanceof InsertStatement; - SQLType sqlType = routeResult.getSqlStatement().getType(); - boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); - Map dataMap = ExecutorDataMap.getDataMap(); - Collection executeResponseUnits = sqlExecuteTemplate.execute(getSQLExecuteUnits(routeResult, isReturnGeneratedKeys), - new FirstMemoryStrictlySQLExecuteCallback(sqlType, isExceptionThrown, dataMap, isReturnGeneratedKeys), - new MemoryStrictlySQLExecuteCallback(sqlType, isExceptionThrown, dataMap, isReturnGeneratedKeys)); - ExecuteResponseUnit firstExecuteResponseUnit = executeResponseUnits.iterator().next(); - return firstExecuteResponseUnit instanceof ExecuteQueryResponseUnit - ? getExecuteQueryResponse(((ExecuteQueryResponseUnit) firstExecuteResponseUnit).getQueryResponsePackets(), executeResponseUnits) : new ExecuteUpdateResponse(executeResponseUnits); - } - - private Collection getSQLExecuteUnits(final SQLRouteResult routeResult, final boolean isReturnGeneratedKeys) throws SQLException { - Collection result = new LinkedList<>(); - List connections = getConnections(routeResult); - int count = 0; - for (RouteUnit each : routeResult.getRouteUnits()) { - Statement statement = getJdbcExecutorWrapper().createStatement(connections.get(count), each.getSqlUnit().getSql(), isReturnGeneratedKeys); - result.add(new StatementExecuteUnit(each, statement)); - count++; - } - return result; - } - - private List getConnections(final SQLRouteResult routeResult) throws SQLException { - List result = new ArrayList<>(routeResult.getRouteUnits().size()); - synchronized (MemoryStrictlyExecuteEngine.class) { - for (RouteUnit each : routeResult.getRouteUnits()) { - result.add(getBackendConnection().getConnection(each.getDataSourceName())); - } - } - return result; - } - - private ExecuteResponse getExecuteQueryResponse(final QueryResponsePackets queryResponsePackets, final Collection executeResponseUnits) { - ExecuteQueryResponse result = new ExecuteQueryResponse(queryResponsePackets); - for (ExecuteResponseUnit each : executeResponseUnits) { - result.getQueryResults().add(((ExecuteQueryResponseUnit) each).getQueryResult()); - } - return result; - } - - @Override - protected QueryResult createQueryResult(final ResultSet resultSet) { - return new StreamQueryResult(resultSet); - } - - private final class FirstMemoryStrictlySQLExecuteCallback extends SQLExecuteCallback { - - private final boolean isReturnGeneratedKeys; - - private FirstMemoryStrictlySQLExecuteCallback(final SQLType sqlType, final boolean isExceptionThrown, final Map dataMap, final boolean isReturnGeneratedKeys) { - super(DatabaseType.MySQL, sqlType, isExceptionThrown, dataMap); - this.isReturnGeneratedKeys = isReturnGeneratedKeys; - } - - @Override - protected ExecuteResponseUnit executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - sqlExecuteUnit.getStatement().setFetchSize(FETCH_ONE_ROW_A_TIME); - return executeWithMetadata(sqlExecuteUnit.getStatement(), sqlExecuteUnit.getRouteUnit().getSqlUnit().getSql(), isReturnGeneratedKeys); - } - } - - private final class MemoryStrictlySQLExecuteCallback extends SQLExecuteCallback { - - private final boolean isReturnGeneratedKeys; - - private MemoryStrictlySQLExecuteCallback(final SQLType sqlType, final boolean isExceptionThrown, final Map dataMap, final boolean isReturnGeneratedKeys) { - super(DatabaseType.MySQL, sqlType, isExceptionThrown, dataMap); - this.isReturnGeneratedKeys = isReturnGeneratedKeys; - } - - @Override - protected ExecuteResponseUnit executeSQL(final SQLExecuteUnit sqlExecuteUnit) throws SQLException { - sqlExecuteUnit.getStatement().setFetchSize(FETCH_ONE_ROW_A_TIME); - return executeWithoutMetadata(sqlExecuteUnit.getStatement(), sqlExecuteUnit.getRouteUnit().getSqlUnit().getSql(), isReturnGeneratedKeys); - } - } -} diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/config/ProxyContext.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/config/ProxyContext.java index 5bd93e43d6660..29786b86e84bf 100644 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/config/ProxyContext.java +++ b/sharding-proxy/src/main/java/io/shardingsphere/proxy/config/ProxyContext.java @@ -18,7 +18,6 @@ package io.shardingsphere.proxy.config; import com.google.common.eventbus.Subscribe; -import io.shardingsphere.core.constant.ConnectionMode; import io.shardingsphere.core.constant.properties.ShardingProperties; import io.shardingsphere.core.constant.properties.ShardingPropertiesConstant; import io.shardingsphere.core.constant.transaction.TransactionType; @@ -69,8 +68,6 @@ public final class ProxyContext { private int executorSize; - private ConnectionMode connectionMode; - private TransactionType transactionType; private BackendNIOConfiguration backendNIOConfig; @@ -112,7 +109,6 @@ public void init(final YamlServerConfiguration serverConfig, final MapgetValue(ShardingPropertiesConstant.CONNECTION_MODE)); maxConnectionsSizePerQuery = shardingProperties.getValue(ShardingPropertiesConstant.MAX_CONNECTIONS_SIZE_PER_QUERY); // TODO just config proxy.transaction.enable here, in future(3.1.0) transactionType = shardingProperties.getValue(ShardingPropertiesConstant.PROXY_TRANSACTION_ENABLED) ? TransactionType.XA : TransactionType.LOCAL; diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/frontend/mysql/MySQLFrontendHandler.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/frontend/mysql/MySQLFrontendHandler.java index d59258f390bd1..98ce7efdcae23 100644 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/frontend/mysql/MySQLFrontendHandler.java +++ b/sharding-proxy/src/main/java/io/shardingsphere/proxy/frontend/mysql/MySQLFrontendHandler.java @@ -22,6 +22,8 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.EventLoopGroup; +import io.shardingsphere.core.event.ShardingEventBusInstance; +import io.shardingsphere.core.event.root.RootInvokeEvent; import io.shardingsphere.proxy.backend.jdbc.connection.BackendConnection; import io.shardingsphere.proxy.config.ProxyContext; import io.shardingsphere.proxy.frontend.common.FrontendHandler; @@ -112,6 +114,7 @@ class CommandExecutor implements Runnable { @Override public void run() { + ShardingEventBusInstance.getInstance().post(new RootInvokeEvent()); try (MySQLPacketPayload payload = new MySQLPacketPayload(message); BackendConnection backendConnection = new BackendConnection(ProxyContext.getInstance().getRuleRegistry(frontendHandler.getCurrentSchema()))) { setBackendConnection(backendConnection); @@ -133,6 +136,9 @@ public void run() { // CHECKSTYLE:ON context.writeAndFlush(new ErrPacket(1, ServerErrorCode.ER_STD_UNKNOWN_EXCEPTION, ex.getMessage())); } + RootInvokeEvent finishEvent = new RootInvokeEvent(); + finishEvent.setExecuteSuccess(); + ShardingEventBusInstance.getInstance().post(finishEvent); } private CommandPacket getCommandPacket(final MySQLPacketPayload payload, final BackendConnection backendConnection, final FrontendHandler frontendHandler) throws SQLException { diff --git a/sharding-proxy/src/main/java/io/shardingsphere/proxy/transport/mysql/packet/command/query/binary/execute/protocol/DateBinaryProtocolValue.java b/sharding-proxy/src/main/java/io/shardingsphere/proxy/transport/mysql/packet/command/query/binary/execute/protocol/DateBinaryProtocolValue.java index 44a087567e90a..6824adb89b444 100644 --- a/sharding-proxy/src/main/java/io/shardingsphere/proxy/transport/mysql/packet/command/query/binary/execute/protocol/DateBinaryProtocolValue.java +++ b/sharding-proxy/src/main/java/io/shardingsphere/proxy/transport/mysql/packet/command/query/binary/execute/protocol/DateBinaryProtocolValue.java @@ -51,12 +51,14 @@ public Object read(final MySQLPacketPayload payload) throws SQLException { } } + @SuppressWarnings("MagicConstant") private Timestamp getTimestampForDate(final MySQLPacketPayload payload) { Calendar result = Calendar.getInstance(); result.set(payload.readInt2(), payload.readInt1() - 1, payload.readInt1()); return new Timestamp(result.getTimeInMillis()); } + @SuppressWarnings("MagicConstant") private Timestamp getTimestampForDatetime(final MySQLPacketPayload payload) { Calendar result = Calendar.getInstance(); result.set(payload.readInt2(), payload.readInt1() - 1, payload.readInt1(), payload.readInt1(), payload.readInt1(), payload.readInt1()); diff --git a/sharding-proxy/src/main/resources/conf/server.yaml b/sharding-proxy/src/main/resources/conf/server.yaml index dda42a20e512f..f15305c9742f2 100644 --- a/sharding-proxy/src/main/resources/conf/server.yaml +++ b/sharding-proxy/src/main/resources/conf/server.yaml @@ -21,8 +21,7 @@ # # # CONNECTION_STRICTLY: Proxy will release connections after get the overall rows from the ResultSet. # # Meanwhile, the cost of the memory will be increased. -# connection.mode: CONNECTION_STRICTLY -# max.connections.size.per.query: 4 +# max.connections.size.per.query: 1 # acceptor.size: 16 # The default value is available processors count * 2. # executor.size: 16 # Infinite by default. # proxy.transaction.enabled: false diff --git a/sharding-proxy/src/test/java/io/shardingsphere/proxy/transport/mysql/packet/command/query/text/query/ComQueryPacketTest.java b/sharding-proxy/src/test/java/io/shardingsphere/proxy/transport/mysql/packet/command/query/text/query/ComQueryPacketTest.java index 6d0aa6861fa32..720611743508f 100644 --- a/sharding-proxy/src/test/java/io/shardingsphere/proxy/transport/mysql/packet/command/query/text/query/ComQueryPacketTest.java +++ b/sharding-proxy/src/test/java/io/shardingsphere/proxy/transport/mysql/packet/command/query/text/query/ComQueryPacketTest.java @@ -24,7 +24,6 @@ import io.shardingsphere.core.constant.transaction.TransactionType; import io.shardingsphere.core.event.ShardingEventBusInstance; import io.shardingsphere.core.event.transaction.xa.XATransactionEvent; -import io.shardingsphere.core.metadata.ShardingMetaData; import io.shardingsphere.proxy.backend.BackendHandler; import io.shardingsphere.proxy.backend.ResultPacket; import io.shardingsphere.proxy.backend.jdbc.connection.BackendConnection; @@ -75,9 +74,6 @@ public final class ComQueryPacketTest { @Mock private FrontendHandler frontendHandler; - @Mock - private RuleRegistry ruleRegistry; - private Listener listener; @Before @@ -104,7 +100,6 @@ private void setProxyContextNIOConfig() throws ReflectiveOperationException { private void setProxyContextRuleRegistryMap() throws ReflectiveOperationException { RuleRegistry ruleRegistry = mock(RuleRegistry.class); - ShardingMetaData metaData = mock(ShardingMetaData.class); Map ruleRegistryMap = new HashMap<>(); ruleRegistryMap.put(ShardingConstant.LOGIC_SCHEMA_NAME, ruleRegistry); Field field = ProxyContext.class.getDeclaredField("ruleRegistryMap"); diff --git a/sharding-sql-test/src/main/resources/sql/dml/update.xml b/sharding-sql-test/src/main/resources/sql/dml/update.xml index 082d41210513a..749a66c5684c8 100644 --- a/sharding-sql-test/src/main/resources/sql/dml/update.xml +++ b/sharding-sql-test/src/main/resources/sql/dml/update.xml @@ -5,4 +5,7 @@ + + +