From 2e341116622dfa0e8d528e3b7d9fb09edb980396 Mon Sep 17 00:00:00 2001 From: c7ch23en Date: Mon, 25 May 2020 17:20:39 +0800 Subject: [PATCH] discard read-only connection --- dal-client/pom.xml | 2 +- .../dal/common/enums/DatabaseCategory.java | 15 +- .../dal/dao/client/ConnectionAction.java | 8 + .../dal/dao/client/DalConnection.java | 32 - .../ctrip/platform/dal/dao/client/DbMeta.java | 2 + .../platform/dal/dao/client/LogEntry.java | 11 +- .../dal/dao/cluster/DynamicCluster.java | 2 +- .../datasource/LocalizedDatabaseMetaData.java | 13 - .../LocalizedDatabaseMetaDataImpl.java | 13 +- .../jdbc/ClusterDatabaseMetaData.java | 14 + .../jdbc/ClusterDatabaseMetaDataImpl.java | 937 ++++++++++++++++++ .../datasource/jdbc/DalCallableStatement.java | 8 +- .../dao/datasource/jdbc/DalConnection.java | 99 +- .../datasource/jdbc/DalDatabaseMetaData.java | 13 + .../datasource/jdbc/DalPreparedStatement.java | 50 +- .../dal/dao/datasource/jdbc/DalStatement.java | 176 +--- .../datasource/LocalizedDataSourceTest.java | 16 +- .../datasource/jdbc/DalConnectionTest.java | 43 + dal-cluster-client/pom.xml | 2 +- pom.xml | 4 +- 20 files changed, 1193 insertions(+), 267 deletions(-) delete mode 100644 dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/LocalizedDatabaseMetaData.java create mode 100644 dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/ClusterDatabaseMetaData.java create mode 100644 dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/ClusterDatabaseMetaDataImpl.java create mode 100644 dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalDatabaseMetaData.java diff --git a/dal-client/pom.xml b/dal-client/pom.xml index 5cb682d6f..b3be6921f 100644 --- a/dal-client/pom.xml +++ b/dal-client/pom.xml @@ -6,7 +6,7 @@ com.ctrip.platform dal-client-parent - 2.0.19-SNAPSHOT + 2.0.19 dal-client jar diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/common/enums/DatabaseCategory.java b/dal-client/src/main/java/com/ctrip/platform/dal/common/enums/DatabaseCategory.java index 830bb0cd2..6f2c1df3a 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/common/enums/DatabaseCategory.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/common/enums/DatabaseCategory.java @@ -23,6 +23,10 @@ public enum DatabaseCategory { MySql("%s=IFNULL(?,%s) ", "CURRENT_TIMESTAMP", new int[] {1043, 1159, 1161}, new int[] {1021, 1037, 1038, 1039, 1040, 1041, 1154, 1158, 1160, 1189, 1190, 1205, 1218, 1219, 1220}) { + private static final String READONLY_EXCEPTION_SQL_STATE = "HY000"; + private static final int READONLY_EXCEPTION_ERROR_CODE = 1290; + private static final String READONLY_EXCEPTION_MESSAGE_KEYWORD = "--read-only"; + private AbstractDalPropertiesLocator mySqlDalPropertiesLocator = DalPropertiesManager.getInstance().getMySqlDalPropertiesLocator(); @@ -54,7 +58,16 @@ public String buildPage(String selectSqlTemplate, int start, int count) { // SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE public boolean isSpecificException(SQLException exception) { Map map = mySqlDalPropertiesLocator.getErrorCodes(); - return matchSpecificError(exception, map); + return matchSpecificError(exception, map) || isReadonlyException(exception); + } + + private boolean isReadonlyException(SQLException exception) { + if (exception != null && READONLY_EXCEPTION_SQL_STATE.equalsIgnoreCase(exception.getSQLState()) && + READONLY_EXCEPTION_ERROR_CODE == exception.getErrorCode()) { + String message = exception.getMessage(); + return message != null && message.toLowerCase().contains(READONLY_EXCEPTION_MESSAGE_KEYWORD); + } + return false; } }, diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/ConnectionAction.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/ConnectionAction.java index d8bee6c6c..0b03e3afa 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/ConnectionAction.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/ConnectionAction.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Set; +import com.ctrip.framework.dal.cluster.client.Cluster; import com.ctrip.platform.dal.common.enums.ShardingCategory; import com.ctrip.platform.dal.common.enums.TableParseSwitch; import com.ctrip.platform.dal.dao.DalClientFactory; @@ -14,6 +15,8 @@ import com.ctrip.platform.dal.dao.DalHints; import com.ctrip.platform.dal.dao.StatementParameters; import com.ctrip.platform.dal.dao.Version; +import com.ctrip.platform.dal.dao.configure.ClusterDatabaseSet; +import com.ctrip.platform.dal.dao.configure.DatabaseSet; import com.ctrip.platform.dal.dao.configure.dalproperties.DalPropertiesLocator; import com.ctrip.platform.dal.dao.configure.dalproperties.DalPropertiesManager; import com.ctrip.platform.dal.dao.task.DalContextConfigure; @@ -156,6 +159,11 @@ public void populateDbMeta() { public void initLogEntry(String logicDbName, DalHints hints) { this.entry = logger.createLogEntry(); + DatabaseSet databaseSet = DalClientFactory.getDalConfigure().getDatabaseSet(logicDbName); + if (databaseSet instanceof ClusterDatabaseSet) { + Cluster cluster = ((ClusterDatabaseSet) databaseSet).getCluster(); + entry.setClusterName(cluster.getClusterName().toLowerCase()); + } entry.setLogicDbName(logicDbName); entry.setDbCategory(DalClientFactory.getDalConfigure().getDatabaseSet(logicDbName).getDatabaseCategory()); entry.setClientVersion(Version.getVersion()); diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/DalConnection.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/DalConnection.java index 3997042b7..5de5ddfb0 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/DalConnection.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/DalConnection.java @@ -19,7 +19,6 @@ public class DalConnection { private String shardId; private DbMeta meta; private DalLogger logger; - private boolean needDiscard; public DalConnection(Connection conn, boolean master, String shardId, DbMeta meta) throws SQLException { this.oldIsolationLevel = conn.getTransactionIsolation(); @@ -66,7 +65,6 @@ public void applyHints(DalHints hints) throws SQLException { } public void error(Throwable e) { - needDiscard |= isSpecificException(e); } public void close() { @@ -85,10 +83,6 @@ public void close() { } try { - if (needDiscard) { - markDiscard(conn); - } - conn.close(); } catch (Throwable e) { logger.error("Close connection failed!", e); @@ -96,30 +90,4 @@ public void close() { conn = null; } - private boolean isSpecificException(Throwable e) { - // Filter wrapping exception - while (e != null && e instanceof DalException) { - e = e.getCause(); - } - - while (e != null && !(e instanceof SQLException)) { - e = e.getCause(); - } - - if (e == null) - return false; - - DatabaseCategory dbCategory = meta.getDatabaseCategory(); - SQLException se = (SQLException) e; - if (dbCategory.isSpecificException(se)) - return true; - - return isSpecificException(se.getNextException()); - } - - private void markDiscard(Connection conn) throws SQLException { - PooledConnection pConn = (PooledConnection) conn.unwrap(PooledConnection.class); - pConn.setDiscarded(true); - } - } diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/DbMeta.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/DbMeta.java index 66da13ccb..df6058178 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/DbMeta.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/DbMeta.java @@ -12,6 +12,7 @@ import com.ctrip.platform.dal.dao.configure.DataSourceConfigureLocatorManager; import com.ctrip.platform.dal.dao.datasource.DataSourceIdentity; import com.ctrip.platform.dal.dao.datasource.DataSourceName; +import com.ctrip.platform.dal.dao.datasource.jdbc.ClusterDatabaseMetaData; import com.ctrip.platform.dal.dao.helper.DalElementFactory; import com.ctrip.platform.dal.dao.helper.LoggerHelper; import com.ctrip.platform.dal.dao.log.ILogger; @@ -60,6 +61,7 @@ private void init(Connection conn, DataSourceIdentity id, DatabaseCategory dbCat } catch (Throwable e) { ilogger.error(e.getMessage(),e); } + } public void populate(LogEntry entry) { diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/LogEntry.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/LogEntry.java index d1c368906..eb78f1077 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/LogEntry.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/client/LogEntry.java @@ -24,6 +24,7 @@ public class LogEntry implements ILogEntry{ private boolean transactional; private long duration; private String logicDbName; + private String clusterName; private DatabaseCategory dbCategory; private String databaseName; private String dataBaseKeyName; @@ -169,7 +170,15 @@ public void setLogicDbName(String logicDbName) { this.logicDbName = logicDbName; } - public DatabaseCategory getDbCategory() { + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public DatabaseCategory getDbCategory() { return dbCategory; } diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/cluster/DynamicCluster.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/cluster/DynamicCluster.java index eb6e4a963..61392bcd5 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/cluster/DynamicCluster.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/cluster/DynamicCluster.java @@ -28,7 +28,7 @@ public class DynamicCluster extends ListenableSupport implements Cluster { private static final ILogger LOGGER = DalElementFactory.DEFAULT.getILogger(); - private static final String CAT_LOG_TYPE = "DAL.cluster"; + private static final String CAT_LOG_TYPE = "DAL.configure"; private static final String CAT_LOG_NAME_FORMAT = "SwitchCluster:%s"; private static final String CAT_EVENT_NAME_NORMAL_TO_DRC = "NormalToDrc:%s"; private static final String CAT_EVENT_NAME_DRC_TO_NORMAL = "DrcToNormal:%s"; diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/LocalizedDatabaseMetaData.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/LocalizedDatabaseMetaData.java deleted file mode 100644 index adee4a1a9..000000000 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/LocalizedDatabaseMetaData.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ctrip.platform.dal.dao.datasource; - -import java.sql.DatabaseMetaData; -import java.sql.SQLException; - -/** - * @author c7ch23en - */ -public interface LocalizedDatabaseMetaData extends DatabaseMetaData { - - String getLocalizedURL() throws SQLException; - -} diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/LocalizedDatabaseMetaDataImpl.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/LocalizedDatabaseMetaDataImpl.java index cd0a6acf1..6ca245608 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/LocalizedDatabaseMetaDataImpl.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/LocalizedDatabaseMetaDataImpl.java @@ -1,20 +1,17 @@ package com.ctrip.platform.dal.dao.datasource; import com.ctrip.framework.dal.cluster.client.config.LocalizationConfig; +import com.ctrip.platform.dal.dao.datasource.jdbc.DalDatabaseMetaData; import java.sql.*; /** * @author c7ch23en */ -public class LocalizedDatabaseMetaDataImpl implements LocalizedDatabaseMetaData { +public class LocalizedDatabaseMetaDataImpl implements DalDatabaseMetaData { - private LocalizationConfig config; - private DatabaseMetaData metaData; - - public LocalizedDatabaseMetaDataImpl(DatabaseMetaData metaData) { - this(null, metaData); - } + private final LocalizationConfig config; + private final DatabaseMetaData metaData; public LocalizedDatabaseMetaDataImpl(LocalizationConfig config, DatabaseMetaData metaData) { this.config = config; @@ -37,7 +34,7 @@ public String getURL() throws SQLException { } @Override - public String getLocalizedURL() throws SQLException { + public String getExtendedURL() throws SQLException { String url = getURL(); if (config != null && config.getZoneId() != null) { url = url + "::" + config.getZoneId().toUpperCase(); diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/ClusterDatabaseMetaData.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/ClusterDatabaseMetaData.java new file mode 100644 index 000000000..e8f600395 --- /dev/null +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/ClusterDatabaseMetaData.java @@ -0,0 +1,14 @@ +package com.ctrip.platform.dal.dao.datasource.jdbc; + +/** + * @author c7ch23en + */ +public interface ClusterDatabaseMetaData extends DalDatabaseMetaData { + + String getClusterName(); + + int getShardIndex(); + + boolean isMaster(); + +} diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/ClusterDatabaseMetaDataImpl.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/ClusterDatabaseMetaDataImpl.java new file mode 100644 index 000000000..14da8842d --- /dev/null +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/ClusterDatabaseMetaDataImpl.java @@ -0,0 +1,937 @@ +package com.ctrip.platform.dal.dao.datasource.jdbc; + +import com.ctrip.framework.dal.cluster.client.database.Database; +import com.ctrip.framework.dal.cluster.client.exception.ClusterRuntimeException; +import com.ctrip.platform.dal.exceptions.DalException; +import com.ctrip.platform.dal.exceptions.DalRuntimeException; + +import java.sql.*; + +/** + * @author c7ch23en + */ +public class ClusterDatabaseMetaDataImpl implements ClusterDatabaseMetaData { + + protected final DatabaseMetaData metaData; + private final Database database; + + public ClusterDatabaseMetaDataImpl(DatabaseMetaData metaData, Database database) { + this.metaData = metaData; + this.database = database; + } + + @Override + public String getClusterName() { + return database.getClusterName(); + } + + @Override + public int getShardIndex() { + return database.getShardIndex(); + } + + @Override + public boolean isMaster() { + return database.isMaster(); + } + + @Override + public boolean allProceduresAreCallable() throws SQLException { + return metaData.allProceduresAreCallable(); + } + + @Override + public boolean allTablesAreSelectable() throws SQLException { + return metaData.allTablesAreSelectable(); + } + + @Override + public String getURL() throws SQLException { + return metaData.getURL(); + } + + @Override + public String getExtendedURL() throws SQLException { + return getURL(); + } + + @Override + public String getUserName() throws SQLException { + return metaData.getUserName(); + } + + @Override + public boolean isReadOnly() throws SQLException { + return metaData.isReadOnly(); + } + + @Override + public boolean nullsAreSortedHigh() throws SQLException { + return metaData.nullsAreSortedHigh(); + } + + @Override + public boolean nullsAreSortedLow() throws SQLException { + return metaData.nullsAreSortedLow(); + } + + @Override + public boolean nullsAreSortedAtStart() throws SQLException { + return metaData.nullsAreSortedAtStart(); + } + + @Override + public boolean nullsAreSortedAtEnd() throws SQLException { + return metaData.nullsAreSortedAtEnd(); + } + + @Override + public String getDatabaseProductName() throws SQLException { + return metaData.getDatabaseProductName(); + } + + @Override + public String getDatabaseProductVersion() throws SQLException { + return metaData.getDatabaseProductVersion(); + } + + @Override + public String getDriverName() throws SQLException { + return metaData.getDriverName(); + } + + @Override + public String getDriverVersion() throws SQLException { + return metaData.getDriverVersion(); + } + + @Override + public int getDriverMajorVersion() { + return metaData.getDriverMajorVersion(); + } + + @Override + public int getDriverMinorVersion() { + return metaData.getDriverMinorVersion(); + } + + @Override + public boolean usesLocalFiles() throws SQLException { + return metaData.usesLocalFiles(); + } + + @Override + public boolean usesLocalFilePerTable() throws SQLException { + return metaData.usesLocalFilePerTable(); + } + + @Override + public boolean supportsMixedCaseIdentifiers() throws SQLException { + return metaData.supportsMixedCaseIdentifiers(); + } + + @Override + public boolean storesUpperCaseIdentifiers() throws SQLException { + return metaData.storesUpperCaseIdentifiers(); + } + + @Override + public boolean storesLowerCaseIdentifiers() throws SQLException { + return metaData.storesLowerCaseIdentifiers(); + } + + @Override + public boolean storesMixedCaseIdentifiers() throws SQLException { + return metaData.storesMixedCaseIdentifiers(); + } + + @Override + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return metaData.supportsMixedCaseQuotedIdentifiers(); + } + + @Override + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return metaData.storesUpperCaseQuotedIdentifiers(); + } + + @Override + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return metaData.storesLowerCaseQuotedIdentifiers(); + } + + @Override + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return metaData.storesMixedCaseQuotedIdentifiers(); + } + + @Override + public String getIdentifierQuoteString() throws SQLException { + return metaData.getIdentifierQuoteString(); + } + + @Override + public String getSQLKeywords() throws SQLException { + return metaData.getSQLKeywords(); + } + + @Override + public String getNumericFunctions() throws SQLException { + return metaData.getNumericFunctions(); + } + + @Override + public String getStringFunctions() throws SQLException { + return metaData.getStringFunctions(); + } + + @Override + public String getSystemFunctions() throws SQLException { + return metaData.getSystemFunctions(); + } + + @Override + public String getTimeDateFunctions() throws SQLException { + return metaData.getTimeDateFunctions(); + } + + @Override + public String getSearchStringEscape() throws SQLException { + return metaData.getSearchStringEscape(); + } + + @Override + public String getExtraNameCharacters() throws SQLException { + return metaData.getExtraNameCharacters(); + } + + @Override + public boolean supportsAlterTableWithAddColumn() throws SQLException { + return metaData.supportsAlterTableWithAddColumn(); + } + + @Override + public boolean supportsAlterTableWithDropColumn() throws SQLException { + return metaData.supportsAlterTableWithDropColumn(); + } + + @Override + public boolean supportsColumnAliasing() throws SQLException { + return metaData.supportsColumnAliasing(); + } + + @Override + public boolean nullPlusNonNullIsNull() throws SQLException { + return metaData.nullPlusNonNullIsNull(); + } + + @Override + public boolean supportsConvert() throws SQLException { + return metaData.supportsConvert(); + } + + @Override + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return metaData.supportsConvert(fromType, toType); + } + + @Override + public boolean supportsTableCorrelationNames() throws SQLException { + return metaData.supportsTableCorrelationNames(); + } + + @Override + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return metaData.supportsDifferentTableCorrelationNames(); + } + + @Override + public boolean supportsExpressionsInOrderBy() throws SQLException { + return metaData.supportsExpressionsInOrderBy(); + } + + @Override + public boolean supportsOrderByUnrelated() throws SQLException { + return metaData.supportsOrderByUnrelated(); + } + + @Override + public boolean supportsGroupBy() throws SQLException { + return metaData.supportsGroupBy(); + } + + @Override + public boolean supportsGroupByUnrelated() throws SQLException { + return metaData.supportsGroupByUnrelated(); + } + + @Override + public boolean supportsGroupByBeyondSelect() throws SQLException { + return metaData.supportsGroupByBeyondSelect(); + } + + @Override + public boolean supportsLikeEscapeClause() throws SQLException { + return metaData.supportsLikeEscapeClause(); + } + + @Override + public boolean supportsMultipleResultSets() throws SQLException { + return metaData.supportsMultipleResultSets(); + } + + @Override + public boolean supportsMultipleTransactions() throws SQLException { + return metaData.supportsMultipleTransactions(); + } + + @Override + public boolean supportsNonNullableColumns() throws SQLException { + return metaData.supportsNonNullableColumns(); + } + + @Override + public boolean supportsMinimumSQLGrammar() throws SQLException { + return metaData.supportsMinimumSQLGrammar(); + } + + @Override + public boolean supportsCoreSQLGrammar() throws SQLException { + return metaData.supportsCoreSQLGrammar(); + } + + @Override + public boolean supportsExtendedSQLGrammar() throws SQLException { + return metaData.supportsExtendedSQLGrammar(); + } + + @Override + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return metaData.supportsANSI92EntryLevelSQL(); + } + + @Override + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return metaData.supportsANSI92IntermediateSQL(); + } + + @Override + public boolean supportsANSI92FullSQL() throws SQLException { + return metaData.supportsANSI92FullSQL(); + } + + @Override + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return metaData.supportsIntegrityEnhancementFacility(); + } + + @Override + public boolean supportsOuterJoins() throws SQLException { + return metaData.supportsOuterJoins(); + } + + @Override + public boolean supportsFullOuterJoins() throws SQLException { + return metaData.supportsFullOuterJoins(); + } + + @Override + public boolean supportsLimitedOuterJoins() throws SQLException { + return metaData.supportsLimitedOuterJoins(); + } + + @Override + public String getSchemaTerm() throws SQLException { + return metaData.getSchemaTerm(); + } + + @Override + public String getProcedureTerm() throws SQLException { + return metaData.getProcedureTerm(); + } + + @Override + public String getCatalogTerm() throws SQLException { + return metaData.getCatalogTerm(); + } + + @Override + public boolean isCatalogAtStart() throws SQLException { + return metaData.isCatalogAtStart(); + } + + @Override + public String getCatalogSeparator() throws SQLException { + return metaData.getCatalogSeparator(); + } + + @Override + public boolean supportsSchemasInDataManipulation() throws SQLException { + return metaData.supportsSchemasInDataManipulation(); + } + + @Override + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return metaData.supportsSchemasInProcedureCalls(); + } + + @Override + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return metaData.supportsSchemasInTableDefinitions(); + } + + @Override + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return metaData.supportsSchemasInIndexDefinitions(); + } + + @Override + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return metaData.supportsSchemasInPrivilegeDefinitions(); + } + + @Override + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return metaData.supportsCatalogsInDataManipulation(); + } + + @Override + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return metaData.supportsCatalogsInProcedureCalls(); + } + + @Override + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return metaData.supportsCatalogsInTableDefinitions(); + } + + @Override + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return metaData.supportsCatalogsInIndexDefinitions(); + } + + @Override + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return metaData.supportsCatalogsInPrivilegeDefinitions(); + } + + @Override + public boolean supportsPositionedDelete() throws SQLException { + return metaData.supportsPositionedDelete(); + } + + @Override + public boolean supportsPositionedUpdate() throws SQLException { + return metaData.supportsPositionedUpdate(); + } + + @Override + public boolean supportsSelectForUpdate() throws SQLException { + return metaData.supportsSelectForUpdate(); + } + + @Override + public boolean supportsStoredProcedures() throws SQLException { + return metaData.supportsStoredProcedures(); + } + + @Override + public boolean supportsSubqueriesInComparisons() throws SQLException { + return metaData.supportsSubqueriesInComparisons(); + } + + @Override + public boolean supportsSubqueriesInExists() throws SQLException { + return metaData.supportsSubqueriesInExists(); + } + + @Override + public boolean supportsSubqueriesInIns() throws SQLException { + return metaData.supportsSubqueriesInIns(); + } + + @Override + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return metaData.supportsSubqueriesInQuantifieds(); + } + + @Override + public boolean supportsCorrelatedSubqueries() throws SQLException { + return metaData.supportsCorrelatedSubqueries(); + } + + @Override + public boolean supportsUnion() throws SQLException { + return metaData.supportsUnion(); + } + + @Override + public boolean supportsUnionAll() throws SQLException { + return metaData.supportsUnionAll(); + } + + @Override + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return metaData.supportsOpenCursorsAcrossCommit(); + } + + @Override + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return metaData.supportsOpenCursorsAcrossRollback(); + } + + @Override + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return metaData.supportsOpenStatementsAcrossCommit(); + } + + @Override + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return metaData.supportsOpenStatementsAcrossRollback(); + } + + @Override + public int getMaxBinaryLiteralLength() throws SQLException { + return metaData.getMaxBinaryLiteralLength(); + } + + @Override + public int getMaxCharLiteralLength() throws SQLException { + return metaData.getMaxCharLiteralLength(); + } + + @Override + public int getMaxColumnNameLength() throws SQLException { + return metaData.getMaxColumnNameLength(); + } + + @Override + public int getMaxColumnsInGroupBy() throws SQLException { + return metaData.getMaxColumnsInGroupBy(); + } + + @Override + public int getMaxColumnsInIndex() throws SQLException { + return metaData.getMaxColumnsInIndex(); + } + + @Override + public int getMaxColumnsInOrderBy() throws SQLException { + return metaData.getMaxColumnsInOrderBy(); + } + + @Override + public int getMaxColumnsInSelect() throws SQLException { + return metaData.getMaxColumnsInSelect(); + } + + @Override + public int getMaxColumnsInTable() throws SQLException { + return metaData.getMaxColumnsInTable(); + } + + @Override + public int getMaxConnections() throws SQLException { + return metaData.getMaxConnections(); + } + + @Override + public int getMaxCursorNameLength() throws SQLException { + return metaData.getMaxCursorNameLength(); + } + + @Override + public int getMaxIndexLength() throws SQLException { + return metaData.getMaxIndexLength(); + } + + @Override + public int getMaxSchemaNameLength() throws SQLException { + return metaData.getMaxSchemaNameLength(); + } + + @Override + public int getMaxProcedureNameLength() throws SQLException { + return metaData.getMaxProcedureNameLength(); + } + + @Override + public int getMaxCatalogNameLength() throws SQLException { + return metaData.getMaxCatalogNameLength(); + } + + @Override + public int getMaxRowSize() throws SQLException { + return metaData.getMaxRowSize(); + } + + @Override + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return metaData.doesMaxRowSizeIncludeBlobs(); + } + + @Override + public int getMaxStatementLength() throws SQLException { + return metaData.getMaxStatementLength(); + } + + @Override + public int getMaxStatements() throws SQLException { + return metaData.getMaxStatements(); + } + + @Override + public int getMaxTableNameLength() throws SQLException { + return metaData.getMaxTableNameLength(); + } + + @Override + public int getMaxTablesInSelect() throws SQLException { + return metaData.getMaxTablesInSelect(); + } + + @Override + public int getMaxUserNameLength() throws SQLException { + return metaData.getMaxUserNameLength(); + } + + @Override + public int getDefaultTransactionIsolation() throws SQLException { + return metaData.getDefaultTransactionIsolation(); + } + + @Override + public boolean supportsTransactions() throws SQLException { + return metaData.supportsTransactions(); + } + + @Override + public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + return metaData.supportsTransactionIsolationLevel(level); + } + + @Override + public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + return metaData.supportsDataDefinitionAndDataManipulationTransactions(); + } + + @Override + public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + return metaData.supportsDataManipulationTransactionsOnly(); + } + + @Override + public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + return metaData.dataDefinitionCausesTransactionCommit(); + } + + @Override + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return metaData.dataDefinitionIgnoredInTransactions(); + } + + @Override + public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { + return metaData.getProcedures(catalog, schemaPattern, procedureNamePattern); + } + + @Override + public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { + return metaData.getProcedureColumns(catalog, schemaPattern, procedureNamePattern, columnNamePattern); + } + + @Override + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException { + return metaData.getTables(catalog, schemaPattern, tableNamePattern, types); + } + + @Override + public ResultSet getSchemas() throws SQLException { + return metaData.getSchemas(); + } + + @Override + public ResultSet getCatalogs() throws SQLException { + return metaData.getCatalogs(); + } + + @Override + public ResultSet getTableTypes() throws SQLException { + return metaData.getTableTypes(); + } + + @Override + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + return metaData.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern); + } + + @Override + public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException { + return metaData.getColumnPrivileges(catalog, schema, table, columnNamePattern); + } + + @Override + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + return metaData.getTablePrivileges(catalog, schemaPattern, tableNamePattern); + } + + @Override + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { + return metaData.getBestRowIdentifier(catalog, schema, table, scope, nullable); + } + + @Override + public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { + return metaData.getVersionColumns(catalog, schema, table); + } + + @Override + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { + return metaData.getPrimaryKeys(catalog, schema, table); + } + + @Override + public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { + return metaData.getImportedKeys(catalog, schema, table); + } + + @Override + public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { + return metaData.getExportedKeys(catalog, schema, table); + } + + @Override + public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + return metaData.getCrossReference(parentCatalog, parentSchema, parentTable, foreignCatalog, foreignSchema, foreignTable); + } + + @Override + public ResultSet getTypeInfo() throws SQLException { + return metaData.getTypeInfo(); + } + + @Override + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { + return metaData.getIndexInfo(catalog, schema, table, unique, approximate); + } + + @Override + public boolean supportsResultSetType(int type) throws SQLException { + return metaData.supportsResultSetType(type); + } + + @Override + public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { + return metaData.supportsResultSetConcurrency(type, concurrency); + } + + @Override + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return metaData.ownUpdatesAreVisible(type); + } + + @Override + public boolean ownDeletesAreVisible(int type) throws SQLException { + return metaData.ownDeletesAreVisible(type); + } + + @Override + public boolean ownInsertsAreVisible(int type) throws SQLException { + return metaData.ownInsertsAreVisible(type); + } + + @Override + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return metaData.othersUpdatesAreVisible(type); + } + + @Override + public boolean othersDeletesAreVisible(int type) throws SQLException { + return metaData.othersDeletesAreVisible(type); + } + + @Override + public boolean othersInsertsAreVisible(int type) throws SQLException { + return metaData.othersInsertsAreVisible(type); + } + + @Override + public boolean updatesAreDetected(int type) throws SQLException { + return metaData.updatesAreDetected(type); + } + + @Override + public boolean deletesAreDetected(int type) throws SQLException { + return metaData.deletesAreDetected(type); + } + + @Override + public boolean insertsAreDetected(int type) throws SQLException { + return metaData.insertsAreDetected(type); + } + + @Override + public boolean supportsBatchUpdates() throws SQLException { + return metaData.supportsBatchUpdates(); + } + + @Override + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { + return metaData.getUDTs(catalog, schemaPattern, typeNamePattern, types); + } + + @Override + public Connection getConnection() throws SQLException { + return metaData.getConnection(); + } + + @Override + public boolean supportsSavepoints() throws SQLException { + return metaData.supportsSavepoints(); + } + + @Override + public boolean supportsNamedParameters() throws SQLException { + return metaData.supportsNamedParameters(); + } + + @Override + public boolean supportsMultipleOpenResults() throws SQLException { + return metaData.supportsMultipleOpenResults(); + } + + @Override + public boolean supportsGetGeneratedKeys() throws SQLException { + return metaData.supportsGetGeneratedKeys(); + } + + @Override + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { + return metaData.getSuperTypes(catalog, schemaPattern, typeNamePattern); + } + + @Override + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + return metaData.getSuperTables(catalog, schemaPattern, tableNamePattern); + } + + @Override + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { + return metaData.getAttributes(catalog, schemaPattern, typeNamePattern, attributeNamePattern); + } + + @Override + public boolean supportsResultSetHoldability(int holdability) throws SQLException { + return metaData.supportsResultSetHoldability(holdability); + } + + @Override + public int getResultSetHoldability() throws SQLException { + return metaData.getResultSetHoldability(); + } + + @Override + public int getDatabaseMajorVersion() throws SQLException { + return metaData.getDatabaseMajorVersion(); + } + + @Override + public int getDatabaseMinorVersion() throws SQLException { + return metaData.getDatabaseMinorVersion(); + } + + @Override + public int getJDBCMajorVersion() throws SQLException { + return metaData.getJDBCMajorVersion(); + } + + @Override + public int getJDBCMinorVersion() throws SQLException { + return metaData.getJDBCMinorVersion(); + } + + @Override + public int getSQLStateType() throws SQLException { + return metaData.getSQLStateType(); + } + + @Override + public boolean locatorsUpdateCopy() throws SQLException { + return metaData.locatorsUpdateCopy(); + } + + @Override + public boolean supportsStatementPooling() throws SQLException { + return metaData.supportsStatementPooling(); + } + + @Override + public RowIdLifetime getRowIdLifetime() throws SQLException { + return metaData.getRowIdLifetime(); + } + + @Override + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { + return metaData.getSchemas(catalog, schemaPattern); + } + + @Override + public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { + return metaData.supportsStoredFunctionsUsingCallSyntax(); + } + + @Override + public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + return metaData.autoCommitFailureClosesAllResultSets(); + } + + @Override + public ResultSet getClientInfoProperties() throws SQLException { + return metaData.getClientInfoProperties(); + } + + @Override + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { + return metaData.getFunctions(catalog, schemaPattern, functionNamePattern); + } + + @Override + public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { + return metaData.getFunctionColumns(catalog, schemaPattern, functionNamePattern, columnNamePattern); + } + + @Override + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + return metaData.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern); + } + + @Override + public boolean generatedKeyAlwaysReturned() throws SQLException { + return metaData.generatedKeyAlwaysReturned(); + } + + @Override + public long getMaxLogicalLobSize() throws SQLException { + return metaData.getMaxLogicalLobSize(); + } + + @Override + public boolean supportsRefCursors() throws SQLException { + return metaData.supportsRefCursors(); + } + + @Override + public T unwrap(Class iface) throws SQLException { + try { + return iface.cast(this); + } catch (ClassCastException e) { + throw new DalRuntimeException(String.format("Unable to unwrap %s to %s", this.toString(), iface.toString())); + } + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return iface.isInstance(this); + } + +} diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalCallableStatement.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalCallableStatement.java index 7a39b48f9..81bc69290 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalCallableStatement.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalCallableStatement.java @@ -1,7 +1,5 @@ package com.ctrip.platform.dal.dao.datasource.jdbc; -import com.ctrip.platform.dal.dao.datasource.RefreshableDataSource; - import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; @@ -11,10 +9,11 @@ import java.util.Map; public class DalCallableStatement extends DalPreparedStatement implements CallableStatement { + private CallableStatement callableStatement; - public DalCallableStatement(CallableStatement callableStatement, RefreshableDataSource dataSource) { - super(callableStatement, dataSource); + public DalCallableStatement(CallableStatement callableStatement, DalConnection connection) { + super(callableStatement, connection); this.callableStatement = callableStatement; } @@ -626,4 +625,5 @@ public void registerOutParameter(String parameterName, SQLType sqlType, int scal public void registerOutParameter(String parameterName, SQLType sqlType, String typeName) throws SQLException { callableStatement.registerOutParameter(parameterName, sqlType, typeName); } + } diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalConnection.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalConnection.java index aca5f6189..ffa0f0560 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalConnection.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalConnection.java @@ -1,14 +1,30 @@ package com.ctrip.platform.dal.dao.datasource.jdbc; +import com.ctrip.platform.dal.common.enums.DatabaseCategory; +import com.ctrip.platform.dal.dao.datasource.ClusterDataSourceIdentity; +import com.ctrip.platform.dal.dao.datasource.DataSourceIdentity; +import com.ctrip.platform.dal.dao.datasource.LocalizedDatabaseMetaDataImpl; import com.ctrip.platform.dal.dao.datasource.RefreshableDataSource; +import com.ctrip.platform.dal.dao.helper.DalElementFactory; +import com.ctrip.platform.dal.dao.helper.LoggerHelper; +import com.ctrip.platform.dal.dao.log.DalLogTypes; +import com.ctrip.platform.dal.dao.log.ILogger; +import com.ctrip.platform.dal.exceptions.DalException; +import org.apache.tomcat.jdbc.pool.PooledConnection; import java.sql.*; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; public class DalConnection implements Connection { + + private static ILogger LOGGER = DalElementFactory.DEFAULT.getILogger(); + private Connection connection; + private List discardCauses = new LinkedList<>(); private RefreshableDataSource dataSource; public DalConnection(Connection connection, RefreshableDataSource dataSource) { @@ -20,19 +36,50 @@ public Connection getConnection() { return connection; } + public void handleException(SQLException e) { + try { + if (isSpecificException(e)) + discardCauses.add(e); + } catch (Throwable t) { + LOGGER.warn("connection handleException exception", t); + } + try { + dataSource.handleException(e); + } catch (Throwable t) { + LOGGER.warn("dataSource handleException exception", t); + } + } + + private boolean isSpecificException(Throwable t) { + Throwable t1 = t; + while (t1 instanceof DalException) { + t1 = t1.getCause(); + } + while (t1 != null && !(t1 instanceof SQLException)) { + t1 = t1.getCause(); + } + if (t1 == null) + return false; + DatabaseCategory dbCategory = dataSource.getSingleDataSource().getDataSourceConfigure().getDatabaseCategory(); + SQLException se = (SQLException) t1; + if (dbCategory.isSpecificException(se)) + return true; + return isSpecificException(se.getNextException()); + } + @Override public Statement createStatement() throws SQLException { - return new DalStatement(connection.createStatement(), dataSource); + return new DalStatement(connection.createStatement(), this); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { - return new DalPreparedStatement(connection.prepareStatement(sql), dataSource); + return new DalPreparedStatement(connection.prepareStatement(sql), this); } @Override public CallableStatement prepareCall(String sql) throws SQLException { - return new DalCallableStatement(connection.prepareCall(sql), dataSource); + return new DalCallableStatement(connection.prepareCall(sql), this); } @Override @@ -62,9 +109,28 @@ public void rollback() throws SQLException { @Override public void close() throws SQLException { + if (discardCauses.size() > 0) { + try { + markDiscard(); + } catch (Throwable t) { + LOGGER.warn("mark connection discarded exception", t); + } finally { + discardCauses.clear(); + } + } connection.close(); } + private void markDiscard() throws SQLException { + long startTime = System.currentTimeMillis(); + PooledConnection conn = connection.unwrap(PooledConnection.class); + conn.setDiscarded(true); + String connUrl = conn.getPoolProperties().getUrl(); + String logName = String.format("Connection::discardConnection:%s", LoggerHelper.getSimplifiedDBUrl(connUrl)); + LOGGER.logTransaction(DalLogTypes.DAL_DATASOURCE, logName, connUrl, startTime); + LOGGER.info(String.format("connection marked discarded: %s", connUrl)); + } + @Override public boolean isClosed() throws SQLException { return connection.isClosed(); @@ -72,7 +138,13 @@ public boolean isClosed() throws SQLException { @Override public DatabaseMetaData getMetaData() throws SQLException { - return connection.getMetaData(); + DatabaseMetaData metaData = connection.getMetaData(); + if (metaData == null) + return null; + DataSourceIdentity id = dataSource.getId(); + if (id instanceof ClusterDataSourceIdentity) + return new ClusterDatabaseMetaDataImpl(metaData, ((ClusterDataSourceIdentity) id).getDatabase()); + return metaData; } @Override @@ -117,17 +189,17 @@ public void clearWarnings() throws SQLException { @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { - return new DalStatement(connection.createStatement(resultSetType, resultSetConcurrency), dataSource); + return new DalStatement(connection.createStatement(resultSetType, resultSetConcurrency), this); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - return new DalPreparedStatement(connection.prepareStatement(sql, resultSetType, resultSetConcurrency), dataSource); + return new DalPreparedStatement(connection.prepareStatement(sql, resultSetType, resultSetConcurrency), this); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - return new DalCallableStatement(connection.prepareCall(sql, resultSetType, resultSetConcurrency), dataSource); + return new DalCallableStatement(connection.prepareCall(sql, resultSetType, resultSetConcurrency), this); } @Override @@ -172,32 +244,32 @@ public void releaseSavepoint(Savepoint savepoint) throws SQLException { @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return new DalStatement(connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability), dataSource); + return new DalStatement(connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability), this); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return new DalPreparedStatement(connection.prepareStatement(sql, resultSetType, resultSetConcurrency), dataSource); + return new DalPreparedStatement(connection.prepareStatement(sql, resultSetType, resultSetConcurrency), this); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return new DalCallableStatement(connection.prepareCall(sql, resultSetType, resultSetHoldability), dataSource); + return new DalCallableStatement(connection.prepareCall(sql, resultSetType, resultSetHoldability), this); } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { - return new DalPreparedStatement(connection.prepareStatement(sql, autoGeneratedKeys), dataSource); + return new DalPreparedStatement(connection.prepareStatement(sql, autoGeneratedKeys), this); } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { - return new DalPreparedStatement(connection.prepareStatement(sql, columnIndexes), dataSource); + return new DalPreparedStatement(connection.prepareStatement(sql, columnIndexes), this); } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { - return new DalPreparedStatement(connection.prepareStatement(sql, columnNames), dataSource); + return new DalPreparedStatement(connection.prepareStatement(sql, columnNames), this); } @Override @@ -289,4 +361,5 @@ public T unwrap(Class iface) throws SQLException { public boolean isWrapperFor(Class iface) throws SQLException { return connection.isWrapperFor(iface); } + } diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalDatabaseMetaData.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalDatabaseMetaData.java new file mode 100644 index 000000000..fa48ddcb0 --- /dev/null +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalDatabaseMetaData.java @@ -0,0 +1,13 @@ +package com.ctrip.platform.dal.dao.datasource.jdbc; + +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +/** + * @author c7ch23en + */ +public interface DalDatabaseMetaData extends DatabaseMetaData { + + String getExtendedURL() throws SQLException; + +} diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalPreparedStatement.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalPreparedStatement.java index 5ec9822dd..c4b05e9dc 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalPreparedStatement.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalPreparedStatement.java @@ -1,7 +1,5 @@ package com.ctrip.platform.dal.dao.datasource.jdbc; -import com.ctrip.platform.dal.dao.datasource.RefreshableDataSource; - import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; @@ -10,13 +8,12 @@ import java.util.Calendar; public class DalPreparedStatement extends DalStatement implements PreparedStatement { + private PreparedStatement preparedStatement; - private RefreshableDataSource dataSource; - public DalPreparedStatement(PreparedStatement preparedStatement, RefreshableDataSource dataSource) { - super(preparedStatement, dataSource); + public DalPreparedStatement(PreparedStatement preparedStatement, DalConnection connection) { + super(preparedStatement, connection); this.preparedStatement = preparedStatement; - this.dataSource = dataSource; } public PreparedStatement getPreparedStatement() { @@ -25,28 +22,12 @@ public PreparedStatement getPreparedStatement() { @Override public ResultSet executeQuery() throws SQLException { - SQLException exception = null; - try { - return preparedStatement.executeQuery(); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> preparedStatement.executeQuery()); } @Override public int executeUpdate() throws SQLException { - SQLException exception = null; - try { - return preparedStatement.executeUpdate(); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> preparedStatement.executeUpdate()); } @Override @@ -151,15 +132,7 @@ public void setObject(int parameterIndex, Object x) throws SQLException { @Override public boolean execute() throws SQLException { - SQLException exception = null; - try { - return preparedStatement.execute(); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> preparedStatement.execute()); } @Override @@ -334,14 +307,7 @@ public void setObject(int parameterIndex, Object x, SQLType targetSqlType) throw @Override public long executeLargeUpdate() throws SQLException { - SQLException exception = null; - try { - return preparedStatement.executeLargeUpdate(); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> preparedStatement.executeLargeUpdate()); } + } diff --git a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalStatement.java b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalStatement.java index 96ade38f4..f198f27a8 100644 --- a/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalStatement.java +++ b/dal-client/src/main/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalStatement.java @@ -1,16 +1,18 @@ package com.ctrip.platform.dal.dao.datasource.jdbc; -import com.ctrip.platform.dal.dao.datasource.RefreshableDataSource; +import com.ctrip.platform.dal.exceptions.DalException; import java.sql.*; +import java.util.concurrent.Callable; public class DalStatement implements Statement { + private Statement statement; - private RefreshableDataSource dataSource; + protected DalConnection connection; - public DalStatement(Statement statement, RefreshableDataSource dataSource) { + public DalStatement(Statement statement, DalConnection connection) { this.statement = statement; - this.dataSource = dataSource; + this.connection = connection; } public Statement getStatement() { @@ -19,29 +21,12 @@ public Statement getStatement() { @Override public ResultSet executeQuery(String sql) throws SQLException { - SQLException exception = null; - try { - return statement.executeQuery(sql); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.executeQuery(sql)); } @Override public int executeUpdate(String sql) throws SQLException { - SQLException exception = null; - try { - return statement.executeUpdate(sql); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } - + return innerExecute(() -> statement.executeUpdate(sql)); } @Override @@ -106,15 +91,7 @@ public void setCursorName(String name) throws SQLException { @Override public boolean execute(String sql) throws SQLException { - SQLException exception = null; - try { - return statement.execute(sql); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.execute(sql)); } @Override @@ -174,15 +151,7 @@ public void clearBatch() throws SQLException { @Override public int[] executeBatch() throws SQLException { - SQLException exception = null; - try { - return statement.executeBatch(); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.executeBatch()); } @Override @@ -202,80 +171,32 @@ public ResultSet getGeneratedKeys() throws SQLException { @Override public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - SQLException exception = null; - try { - return statement.executeUpdate(sql, autoGeneratedKeys); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.executeUpdate(sql, autoGeneratedKeys)); } @Override public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { - SQLException exception = null; - try { - return statement.executeUpdate(sql, columnIndexes); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.executeUpdate(sql, columnIndexes)); } @Override public int executeUpdate(String sql, String[] columnNames) throws SQLException { - SQLException exception = null; - try { - return statement.executeUpdate(sql, columnNames); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.executeUpdate(sql, columnNames)); } @Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { - SQLException exception = null; - try { - return statement.execute(sql, autoGeneratedKeys); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.execute(sql, autoGeneratedKeys)); } @Override public boolean execute(String sql, int[] columnIndexes) throws SQLException { - SQLException exception = null; - try { - return statement.execute(sql, columnIndexes); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.execute(sql, columnIndexes)); } @Override public boolean execute(String sql, String[] columnNames) throws SQLException { - SQLException exception = null; - try { - return statement.execute(sql, columnNames); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.execute(sql, columnNames)); } @Override @@ -325,67 +246,27 @@ public long getLargeMaxRows() throws SQLException { @Override public long[] executeLargeBatch() throws SQLException { - SQLException exception = null; - try { - return statement.executeLargeBatch(); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.executeLargeBatch()); } @Override public long executeLargeUpdate(String sql) throws SQLException { - SQLException exception = null; - try { - return statement.executeLargeUpdate(sql); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.executeLargeUpdate(sql)); } @Override public long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - SQLException exception = null; - try { - return statement.executeLargeUpdate(sql, autoGeneratedKeys); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.executeLargeUpdate(sql, autoGeneratedKeys)); } @Override public long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException { - SQLException exception = null; - try { - return statement.executeLargeUpdate(sql, columnIndexes); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.executeLargeUpdate(sql, columnIndexes)); } @Override public long executeLargeUpdate(String sql, String[] columnNames) throws SQLException { - SQLException exception = null; - try { - return statement.executeLargeUpdate(sql, columnNames); - } catch (SQLException e) { - exception = e; - throw e; - } finally { - dataSource.handleException(exception); - } + return innerExecute(() -> statement.executeLargeUpdate(sql, columnNames)); } @Override @@ -397,4 +278,19 @@ public T unwrap(Class iface) throws SQLException { public boolean isWrapperFor(Class iface) throws SQLException { return statement.isWrapperFor(iface); } + + protected T innerExecute(Callable task) throws SQLException { + SQLException exception = null; + try { + return task.call(); + } catch (SQLException e) { + exception = e; + throw e; + } catch (Exception ex) { + throw new DalException("innerExecute exception", ex); + } finally { + connection.handleException(exception); + } + } + } diff --git a/dal-client/src/test/java/com/ctrip/platform/dal/dao/datasource/LocalizedDataSourceTest.java b/dal-client/src/test/java/com/ctrip/platform/dal/dao/datasource/LocalizedDataSourceTest.java index 121e357d0..4998fb6b2 100644 --- a/dal-client/src/test/java/com/ctrip/platform/dal/dao/datasource/LocalizedDataSourceTest.java +++ b/dal-client/src/test/java/com/ctrip/platform/dal/dao/datasource/LocalizedDataSourceTest.java @@ -50,8 +50,8 @@ public void testNormalDataSource() throws SQLException { private void testStatementBlocked(DataSource dataSource) throws SQLException { Connection connection = dataSource.getConnection(); DatabaseMetaData metaData = connection.getMetaData(); - Assert.assertTrue(metaData instanceof LocalizedDatabaseMetaData); - String url = ((LocalizedDatabaseMetaData) metaData).getLocalizedURL(); + Assert.assertTrue(metaData instanceof LocalizedDatabaseMetaDataImpl); + String url = ((LocalizedDatabaseMetaDataImpl) metaData).getExtendedURL(); Assert.assertTrue(url.endsWith(TEST_ZONE.toUpperCase())); Statement statement = connection.createStatement(); @@ -169,8 +169,8 @@ private void testStatementBlocked(DataSource dataSource) throws SQLException { private void testPreparedStatementBlocked(DataSource dataSource) throws SQLException { Connection connection = dataSource.getConnection(); DatabaseMetaData metaData = connection.getMetaData(); - Assert.assertTrue(metaData instanceof LocalizedDatabaseMetaData); - String url = ((LocalizedDatabaseMetaData) metaData).getLocalizedURL(); + Assert.assertTrue(metaData instanceof LocalizedDatabaseMetaDataImpl); + String url = ((LocalizedDatabaseMetaDataImpl) metaData).getExtendedURL(); Assert.assertTrue(url.endsWith(TEST_ZONE.toUpperCase())); // executeQuery @@ -258,8 +258,8 @@ private void testPreparedStatementBlocked(DataSource dataSource) throws SQLExcep private void testStatementPassed(DataSource dataSource) throws SQLException { Connection connection = dataSource.getConnection(); DatabaseMetaData metaData = connection.getMetaData(); - Assert.assertTrue(metaData instanceof LocalizedDatabaseMetaData); - String url = metaData.getURL(); + Assert.assertTrue(metaData instanceof LocalizedDatabaseMetaDataImpl); + String url = ((LocalizedDatabaseMetaDataImpl) metaData).getExtendedURL(); Assert.assertTrue(url.endsWith("UTF-8")); Statement statement = connection.createStatement(); @@ -312,8 +312,8 @@ private void testStatementPassed(DataSource dataSource) throws SQLException { private void testPreparedStatementPassed(DataSource dataSource) throws SQLException { Connection connection = dataSource.getConnection(); DatabaseMetaData metaData = connection.getMetaData(); - Assert.assertTrue(metaData instanceof LocalizedDatabaseMetaData); - String url = metaData.getURL(); + Assert.assertTrue(metaData instanceof LocalizedDatabaseMetaDataImpl); + String url = ((LocalizedDatabaseMetaDataImpl) metaData).getExtendedURL(); Assert.assertTrue(url.endsWith("UTF-8")); // executeQuery diff --git a/dal-client/src/test/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalConnectionTest.java b/dal-client/src/test/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalConnectionTest.java index ec5fa7206..4a0ab8dc2 100644 --- a/dal-client/src/test/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalConnectionTest.java +++ b/dal-client/src/test/java/com/ctrip/platform/dal/dao/datasource/jdbc/DalConnectionTest.java @@ -2,11 +2,15 @@ import com.ctrip.platform.dal.dao.configure.DataSourceConfigure; import com.ctrip.platform.dal.dao.datasource.RefreshableDataSource; +import org.apache.tomcat.jdbc.pool.PooledConnection; import org.junit.Assert; import org.junit.Test; +import javax.sql.DataSource; import java.sql.*; +import java.util.Date; import java.util.Properties; +import java.util.concurrent.TimeUnit; import static com.ctrip.platform.dal.dao.configure.DataSourceConfigureConstants.*; @@ -57,4 +61,43 @@ public void testStatementType() throws SQLException { } callableStatement.close(); } + +// @Test + public void testDiscardConnection() throws SQLException { + Properties p = new Properties(); + p.setProperty(USER_NAME, "tt_daltest_3"); + p.setProperty(PASSWORD, "R0NeM30TcbAfWz7aHoWx"); + p.setProperty(CONNECTION_URL, "jdbc:mysql://10.2.22.223:55777/dalservice2db?useUnicode=true&characterEncoding=UTF-8"); + p.setProperty(DRIVER_CLASS_NAME, "com.mysql.jdbc.Driver"); + DataSourceConfigure c = new DataSourceConfigure("dalservice2db", p); + RefreshableDataSource ds = new RefreshableDataSource("dalservice2db", c); + PooledConnection pConn = null; + try (Connection connection = ds.getConnection()) { + pConn = connection.unwrap(PooledConnection.class); + System.out.println("discarded0: " + pConn.isDiscarded()); + try { +// PreparedStatement ps = connection.prepareStatement("select * from person5756 where id > 0"); +// ResultSet rs = ps.executeQuery(); +// System.out.println("result set: " + rs); + PreparedStatement ps = connection.prepareStatement("update person33 set name = 'testDiscard' where id > 0"); + int rows = ps.executeUpdate(); + System.out.println("affected rows: " + rows); + System.out.println("discarded1: " + pConn.isDiscarded()); + } catch (SQLException e) { + System.out.println("error: " + e); + System.out.println("error: " + e.getErrorCode()); + e.printStackTrace(); + System.out.println("discarded2: " + pConn.isDiscarded()); + throw e; + } finally { +// connection.close(); + System.out.println("discarded3: " + pConn.isDiscarded()); + } + } catch (Throwable t) { + // ignore + } + if (pConn != null) + System.out.println("discarded4: " + pConn.isDiscarded()); + } + } diff --git a/dal-cluster-client/pom.xml b/dal-cluster-client/pom.xml index fbc9c43ec..b169e0829 100644 --- a/dal-cluster-client/pom.xml +++ b/dal-cluster-client/pom.xml @@ -6,7 +6,7 @@ com.ctrip.platform dal-client-parent - 2.0.19-SNAPSHOT + 2.0.19 com.ctrip.framework.dal dal-cluster-client diff --git a/pom.xml b/pom.xml index 1d7860e5c..fe8eeafcc 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.ctrip.platform dal-client-parent - 2.0.19-SNAPSHOT + 2.0.19 pom @@ -29,7 +29,7 @@ 2.5 1.0.2 7.0.52 - 5.1.48 + 5.1.39 6.4.0.jre7.ctrip 1.2 2.8.0