diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 05291f2077..f6edcd85ad 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -67,18 +67,7 @@ import com.alibaba.druid.filter.Filter; import com.alibaba.druid.filter.FilterChainImpl; import com.alibaba.druid.mock.MockDriver; import com.alibaba.druid.pool.DruidPooledPreparedStatement.PreparedStatementKey; -import com.alibaba.druid.pool.vendor.DB2ExceptionSorter; -import com.alibaba.druid.pool.vendor.InformixExceptionSorter; -import com.alibaba.druid.pool.vendor.MSSQLValidConnectionChecker; -import com.alibaba.druid.pool.vendor.MockExceptionSorter; -import com.alibaba.druid.pool.vendor.MySqlExceptionSorter; -import com.alibaba.druid.pool.vendor.MySqlValidConnectionChecker; -import com.alibaba.druid.pool.vendor.NullExceptionSorter; -import com.alibaba.druid.pool.vendor.OracleExceptionSorter; -import com.alibaba.druid.pool.vendor.OracleValidConnectionChecker; -import com.alibaba.druid.pool.vendor.PGExceptionSorter; -import com.alibaba.druid.pool.vendor.PGValidConnectionChecker; -import com.alibaba.druid.pool.vendor.SybaseExceptionSorter; +import com.alibaba.druid.pool.vendor.*; import com.alibaba.druid.proxy.DruidDriver; import com.alibaba.druid.proxy.jdbc.DataSourceProxyConfig; import com.alibaba.druid.proxy.jdbc.TransactionInfo; @@ -1346,6 +1335,12 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } else if (realDriverClassName.equals(JdbcConstants.ORACLE_DRIVER) || realDriverClassName.equals(JdbcConstants.ORACLE_DRIVER2)) { this.exceptionSorter = new OracleExceptionSorter(); + } else if (realDriverClassName.equals(JdbcConstants.OCEANBASE_DRIVER)) { + if (JdbcUtils.OCEANBASE_ORACLE.equalsIgnoreCase(dbType)) { + this.exceptionSorter = new OceanBaseOracleExceptionSorter(); + } else { + this.exceptionSorter = new MySqlExceptionSorter(); + } } else if (realDriverClassName.equals("com.informix.jdbc.IfxDriver")) { this.exceptionSorter = new InformixExceptionSorter(); diff --git a/src/main/java/com/alibaba/druid/pool/vendor/OceanBaseOracleExceptionSorter.java b/src/main/java/com/alibaba/druid/pool/vendor/OceanBaseOracleExceptionSorter.java new file mode 100644 index 0000000000..6cdeac49be --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/vendor/OceanBaseOracleExceptionSorter.java @@ -0,0 +1,143 @@ +package com.alibaba.druid.pool.vendor; + +import java.io.Serializable; +import java.sql.SQLException; +import java.sql.SQLRecoverableException; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +import com.alibaba.druid.pool.ExceptionSorter; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; + +public class OceanBaseOracleExceptionSorter extends OracleExceptionSorter { + + private final static Log LOG = LogFactory.getLog(OracleExceptionSorter.class); + private static final long serialVersionUID = -9146226891418913174L; + private Set fatalErrorCodes = new HashSet(); + + public OceanBaseOracleExceptionSorter() { + configFromProperties(System.getProperties()); + } + + public void configFromProperties(Properties properties) { + String property = properties.getProperty("druid.oracle.fatalErrorCodes"); + if (property != null) { + String[] items = property.split("\\,"); + for (String item : items) { + if (item != null && item.length() > 0) { + try { + int code = Integer.parseInt(item); + fatalErrorCodes.add(code); + } catch (NumberFormatException e) { + LOG.error("parse druid.oracle.fatalErrorCodes error", e); + } + } + } + } + } + + public Set getFatalErrorCodes() { + return fatalErrorCodes; + } + + public void setFatalErrorCodes(Set fatalErrorCodes) { + this.fatalErrorCodes = fatalErrorCodes; + } + + @Override + public boolean isExceptionFatal(SQLException e) { + if (e instanceof SQLRecoverableException) { + return true; + } + final String sqlState = e.getSQLState(); + final int error_code = Math.abs(e.getErrorCode()); // I can't remember if the errors are negative or positive. + if (sqlState != null && sqlState.startsWith("08")) { + return true; + } + switch (error_code) { + case 28: // your session has been killed + case 600: // Internal oracle error + case 1012: // not logged on + case 1014: // Oracle shutdown in progress + case 1033: // Oracle initialization or shutdown in progress + case 1034: // Oracle not available + case 1035: // ORACLE only available to users with RESTRICTED SESSION privilege + case 1089: // immediate shutdown in progress - no operations are permitted + case 1090: // shutdown in progress - connection is not permitted + case 1092: // ORACLE instance terminated. Disconnection forced + case 1094: // ALTER DATABASE CLOSE in progress. Connections not permitted + case 2396: // exceeded maximum idle time, please connect again + case 3106: // fatal two-task communication protocol error + case 3111: // break received on communication channel + case 3113: // end-of-file on communication channel + case 3114: // not connected to ORACLE + case 3134: // Connections to this server version are no longer supported. + case 3135: // connection lost contact + case 3136: // inbound connection timed out + case 3138: // Connection terminated due to security policy violation + case 3142: // Connection was lost for the specified session and serial number. This is either due to session + // being killed or network problems. + case 3143: // Connection was lost for the specified process ID and thread ID. This is either due to session + // being killed or network problems. + case 3144: // Connection was lost for the specified process ID. This is either due to session being killed + // or network problems. + case 3145: // I/O streaming direction error + case 3149: // Invalid Oracle error code, Cause: An invalid Oracle error code was received by the server. + case 6801: // TLI Driver: listen for SPX server reconnect failed + case 6802: // TLI Driver: could not open the /etc/netware/yellowpages file + case 6805: // TLI Driver: could not send datagram SAP packet for SPX + case 9918: // Unable to get user privileges from SQL*Net + case 9920: // Unable to get sensitivity label from connection + case 9921: // Unable to get information label from connection + // TTC(Two-Task Common) ERROR CODE + case 17001: // Internal Error + case 17002: // Io exception + case 17008: // Closed Connection + case 17009: // Closed Statement + case 17024: // No data read + case 17089: // internal error + case 17409: // invalid buffer length + case 17401: // Protocol violation + case 17410: // No more data to read from socket + case 17416: // FATAl + case 17438: // Internal - Unexpected value + case 17442: // Refcursor value is invalid + case 25407: // connection terminated + case 25408: // can not safely replay call + case 25409: // failover happened during the network operation,cannot continue + case 25425: // connection lost during rollback + case 29276: // transfer timeout + case 30676: // socket read or write failed + return true; + default: + if (error_code >= 12100 && error_code <= 12299) { // TNS issues + return true; + } + break; + } + final String error_text = (e.getMessage()).toUpperCase(); + // Exclude oracle user defined error codes (20000 through 20999) from consideration when looking for + // certain strings. + if ((error_code < 20000 || error_code >= 21000)) { + if ((error_text.contains("SOCKET")) // for control socket error + || (error_text.contains("套接字")) // for control socket error + || (error_text.contains("CONNECTION HAS ALREADY BEEN CLOSED")) // + || (error_text.contains("BROKEN PIPE")) // + || (error_text.contains("管道已结束")) // + ) { + return true; + } + } + if (error_text.indexOf("COMMUNICATIONS LINK FAILURE") > -1 + || error_text.indexOf("COULD NOT CREATE CONNECTION") > -1 + || error_text.indexOf("ACCESS DENIED FOR USER") > -1 + || error_text.indexOf("NO DATASOURCE") > -1 + || error_text.indexOf("NO ALIVE DATASOURCE") > -1) {// errorCode忽略并且异常信息为连接出错 + return true; + } + + return fatalErrorCodes.contains(error_code); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/exception/OceanBaseOracleExceptionSorterTest.java b/src/test/java/com/alibaba/druid/bvt/pool/exception/OceanBaseOracleExceptionSorterTest.java new file mode 100644 index 0000000000..347dfb0b7d --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/exception/OceanBaseOracleExceptionSorterTest.java @@ -0,0 +1,78 @@ +package com.alibaba.druid.bvt.pool.exception; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledConnection; +import com.alibaba.druid.pool.vendor.OceanBaseOracleExceptionSorter; +import com.alibaba.druid.pool.vendor.OracleExceptionSorter; +import com.alibaba.druid.stat.JdbcStatManager; +import com.alibaba.druid.test.util.OracleMockDriver; +import com.alibaba.druid.util.JdbcUtils; +import junit.framework.TestCase; +import org.junit.Assert; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class OceanBaseOracleExceptionSorterTest extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + Assert.assertEquals(0, JdbcStatManager.getInstance().getSqlList().size()); + + dataSource = new DruidDataSource(); + + dataSource.setExceptionSorter(new OceanBaseOracleExceptionSorter()); + + dataSource.setDriver(new OracleMockDriver()); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setPoolPreparedStatements(true); + dataSource.setMaxOpenPreparedStatements(100); + dataSource.setFilters("log4j"); + } + + @Override + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + } + + public void test_connect() throws Exception { + String sql = "SELECT 1"; + { + DruidPooledConnection conn = dataSource.getConnection(); + + PreparedStatement pstmt = conn.prepareStatement(sql); + pstmt.execute(); + pstmt.close(); + conn.close(); + } + + DruidPooledConnection conn = dataSource.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(sql); + pstmt.setFetchSize(1000); + + SQLException exception = new SQLException("xx", "xxx", 28); + boolean fatal = false; + try { + conn.handleException(exception); + } catch (SQLException ex) { + fatal = true; + } + Assert.assertTrue(fatal); + + pstmt.close(); + + SQLException commitError = null; + try { + conn.commit(); + } catch (SQLException ex) { + commitError = ex; + } + + Assert.assertNotNull(commitError); + Assert.assertSame(exception, commitError.getCause()); + + conn.close(); + } + +}