druid?handleException執(zhí)行流程源碼解析
序
本文主要研究一下druid的handleException
prepareStatement
com/alibaba/druid/pool/DruidPooledConnection.java
public PreparedStatement prepareStatement(String sql) throws SQLException {
checkState();
PreparedStatementHolder stmtHolder = null;
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M1);
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
if (poolPreparedStatements) {
stmtHolder = holder.getStatementPool().get(key);
}
if (stmtHolder == null) {
try {
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql));
holder.getDataSource().incrementPreparedStatementCount();
} catch (SQLException ex) {
handleException(ex, sql);
}
}
initStatement(stmtHolder);
DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder);
holder.addTrace(rtnVal);
return rtnVal;
}DruidPooledConnection的prepareStatement會(huì)catch住SQLException然后執(zhí)行handleException
executeQuery
com/alibaba/druid/pool/DruidPooledPreparedStatement.java
public ResultSet executeQuery() throws SQLException {
checkOpen();
incrementExecuteQueryCount();
transactionRecord(sql);
oracleSetRowPrefetch();
conn.beforeExecute();
try {
ResultSet rs = stmt.executeQuery();
if (rs == null) {
return null;
}
DruidPooledResultSet poolableResultSet = new DruidPooledResultSet(this, rs);
addResultSetTrace(poolableResultSet);
return poolableResultSet;
} catch (Throwable t) {
errorCheck(t);
throw checkException(t);
} finally {
conn.afterExecute();
}
}executeQuery在catch到Throwable時(shí)會(huì)執(zhí)行throw checkException(t)
checkException
com/alibaba/druid/pool/DruidPooledStatement.java
protected SQLException checkException(Throwable error) throws SQLException {
String sql = null;
if (this instanceof DruidPooledPreparedStatement) {
sql = ((DruidPooledPreparedStatement) this).getSql();
}
handleSocketTimeout(error);
exceptionCount++;
return conn.handleException(error, sql);
}checkException這里會(huì)執(zhí)行conn.handleException(error, sql)
handleException
public SQLException handleException(Throwable t, String sql) throws SQLException {
final DruidConnectionHolder holder = this.holder;
//
if (holder != null) {
DruidAbstractDataSource dataSource = holder.getDataSource();
dataSource.handleConnectionException(this, t, sql);
}
if (t instanceof SQLException) {
throw (SQLException) t;
}
throw new SQLException("Error", t);
}handleException這里是委托給了dataSource.handleConnectionException(this, t, sql);
handleConnectionException
com/alibaba/druid/pool/DruidDataSource.java
public void handleConnectionException(DruidPooledConnection pooledConnection,
Throwable t,
String sql) throws SQLException {
final DruidConnectionHolder holder = pooledConnection.getConnectionHolder();
if (holder == null) {
return;
}
errorCountUpdater.incrementAndGet(this);
lastError = t;
lastErrorTimeMillis = System.currentTimeMillis();
if (t instanceof SQLException) {
SQLException sqlEx = (SQLException) t;
// broadcastConnectionError
ConnectionEvent event = new ConnectionEvent(pooledConnection, sqlEx);
for (ConnectionEventListener eventListener : holder.getConnectionEventListeners()) {
eventListener.connectionErrorOccurred(event);
}
// exceptionSorter.isExceptionFatal
if (exceptionSorter != null && exceptionSorter.isExceptionFatal(sqlEx)) {
handleFatalError(pooledConnection, sqlEx, sql);
}
throw sqlEx;
} else {
throw new SQLException("Error", t);
}
}handleConnectionException方法在exceptionSorter.isExceptionFatal(sqlEx)為true時(shí)會(huì)執(zhí)行handleFatalError
isExceptionFatal
com/alibaba/druid/pool/vendor/MySqlExceptionSorter.java
public class MySqlExceptionSorter implements ExceptionSorter {
@Override
public boolean isExceptionFatal(SQLException e) {
if (e instanceof SQLRecoverableException) {
return true;
}
final String sqlState = e.getSQLState();
final int errorCode = e.getErrorCode();
if (sqlState != null && sqlState.startsWith("08")) {
return true;
}
switch (errorCode) {
// Communications Errors
case 1040: // ER_CON_COUNT_ERROR
case 1042: // ER_BAD_HOST_ERROR
case 1043: // ER_HANDSHAKE_ERROR
case 1047: // ER_UNKNOWN_COM_ERROR
case 1081: // ER_IPSOCK_ERROR
case 1129: // ER_HOST_IS_BLOCKED
case 1130: // ER_HOST_NOT_PRIVILEGED
// Authentication Errors
case 1045: // ER_ACCESS_DENIED_ERROR
// Resource errors
case 1004: // ER_CANT_CREATE_FILE
case 1005: // ER_CANT_CREATE_TABLE
case 1015: // ER_CANT_LOCK
case 1021: // ER_DISK_FULL
case 1041: // ER_OUT_OF_RESOURCES
// Out-of-memory errors
case 1037: // ER_OUTOFMEMORY
case 1038: // ER_OUT_OF_SORTMEMORY
// Access denied
case 1142: // ER_TABLEACCESS_DENIED_ERROR
case 1227: // ER_SPECIFIC_ACCESS_DENIED_ERROR
case 1023: // ER_ERROR_ON_CLOSE
case 1290: // ER_OPTION_PREVENTS_STATEMENT
return true;
default:
break;
}
// for oceanbase
if (errorCode >= -9000 && errorCode <= -8000) {
return true;
}
String className = e.getClass().getName();
if (className.endsWith(".CommunicationsException")) {
return true;
}
String message = e.getMessage();
if (message != null && message.length() > 0) {
if (message.startsWith("Streaming result set com.mysql.jdbc.RowDataDynamic")
&& message.endsWith("is still active. No statements may be issued when any streaming result sets are open and in use on a given connection. Ensure that you have called .close() on any active streaming result sets before attempting more queries.")) {
return true;
}
final String errorText = message.toUpperCase();
if ((errorCode == 0 && (errorText.contains("COMMUNICATIONS LINK FAILURE")) //
|| errorText.contains("COULD NOT CREATE CONNECTION")) //
|| errorText.contains("NO DATASOURCE") //
|| errorText.contains("NO ALIVE DATASOURCE")) {
return true;
}
}
Throwable cause = e.getCause();
for (int i = 0; i < 5 && cause != null; ++i) {
if (cause instanceof SocketTimeoutException) {
return true;
}
className = cause.getClass().getName();
if (className.endsWith(".CommunicationsException")) {
return true;
}
cause = cause.getCause();
}
return false;
}
@Override
public void configFromProperties(Properties properties) {
}
}MySqlExceptionSorter針對(duì)指定錯(cuò)誤碼來(lái)判斷是否fatal
handleFatalError
com/alibaba/druid/pool/DruidDataSource.java
protected final void handleFatalError(DruidPooledConnection conn,
SQLException error,
String sql) throws SQLException {
final DruidConnectionHolder holder = conn.holder;
if (conn.isTraceEnable()) {
activeConnectionLock.lock();
try {
if (conn.isTraceEnable()) {
activeConnections.remove(conn);
conn.setTraceEnable(false);
}
} finally {
activeConnectionLock.unlock();
}
}
long lastErrorTimeMillis = this.lastErrorTimeMillis;
if (lastErrorTimeMillis == 0) {
lastErrorTimeMillis = System.currentTimeMillis();
}
if (sql != null && sql.length() > 1024) {
sql = sql.substring(0, 1024);
}
boolean requireDiscard = false;
final ReentrantLock lock = conn.lock;
lock.lock();
try {
if ((!conn.isClosed()) || !conn.isDisable()) {
conn.disable(error);
requireDiscard = true;
}
lastFatalErrorTimeMillis = lastErrorTimeMillis;
fatalErrorCount++;
if (fatalErrorCount - fatalErrorCountLastShrink > onFatalErrorMaxActive) {
onFatalError = true;
}
lastFatalError = error;
lastFatalErrorSql = sql;
} finally {
lock.unlock();
}
if (onFatalError && holder != null && holder.getDataSource() != null) {
ReentrantLock dataSourceLock = holder.getDataSource().lock;
dataSourceLock.lock();
try {
emptySignal();
} finally {
dataSourceLock.unlock();
}
}
if (requireDiscard) {
if (holder.statementTrace != null) {
holder.lock.lock();
try {
for (Statement stmt : holder.statementTrace) {
JdbcUtils.close(stmt);
}
} finally {
holder.lock.unlock();
}
}
this.discardConnection(holder);
}
// holder.
LOG.error("{conn-" + holder.getConnectionId() + "} discard", error);
}handleFatalError方法這里會(huì)執(zhí)行conn.disable(error),然后標(biāo)記requireDiscard為true,最后執(zhí)行discardConnection
discardConnection
com/alibaba/druid/pool/DruidDataSource.java
public void discardConnection(DruidConnectionHolder holder) {
if (holder == null) {
return;
}
Connection conn = holder.getConnection();
if (conn != null) {
JdbcUtils.close(conn);
}
lock.lock();
try {
if (holder.discard) {
return;
}
if (holder.active) {
activeCount--;
holder.active = false;
}
discardCount++;
holder.discard = true;
if (activeCount <= minIdle) {
emptySignal();
}
} finally {
lock.unlock();
}
}discardConnection這里會(huì)通過(guò)JdbcUtils.close(conn)關(guān)閉連接,然后加鎖判斷是否小于等于minIdle,若為true則執(zhí)行emptySignal
小結(jié)
druid會(huì)在prepareStatement或者執(zhí)行prepareStatement出現(xiàn)異常的時(shí)候執(zhí)行conn.handleException,它委托給dataSource.handleConnectionException,后者會(huì)在exceptionSorter.isExceptionFatal(sqlEx)為true時(shí)會(huì)執(zhí)行handleFatalError,handleFatalError方法這里會(huì)執(zhí)行conn.disable(error),然后標(biāo)記requireDiscard為true,最后執(zhí)行discardConnection來(lái)關(guān)閉連接。通過(guò)這樣子來(lái)快速清理不可用的連接,避免連接池的連接不可用。
以上就是druid handleException執(zhí)行流程源碼解析的詳細(xì)內(nèi)容,更多關(guān)于druid handleException執(zhí)行的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于SpringBoot+Redis實(shí)現(xiàn)分布式鎖
本文主要介紹了基于SpringBoot+Redis實(shí)現(xiàn)分布式鎖,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
Javabean基于xstream包實(shí)現(xiàn)轉(zhuǎn)XML文檔的方法
這篇文章主要介紹了Javabean基于xstream包實(shí)現(xiàn)轉(zhuǎn)XML文檔的方法,結(jié)合具體實(shí)例形式分析了xstream包用于轉(zhuǎn)換xml文件的具體使用技巧,需要的朋友可以參考下2017-05-05
SpringMVC使用自定義驗(yàn)證器進(jìn)行數(shù)據(jù)驗(yàn)證的方法
SpringMVC?提供了強(qiáng)大的數(shù)據(jù)驗(yàn)證機(jī)制,可以方便地驗(yàn)證表單提交的數(shù)據(jù),除了自帶的驗(yàn)證器之外,SpringMVC?還支持自定義驗(yàn)證器,允許開(kāi)發(fā)者根據(jù)業(yè)務(wù)需求自定義驗(yàn)證規(guī)則,本文將介紹如何在?SpringMVC?中使用自定義驗(yàn)證器2023-07-07
Java FTPClient實(shí)現(xiàn)文件上傳下載
這篇文章主要為大家詳細(xì)介紹了Java FTPClient實(shí)現(xiàn)文件上傳下載的相關(guān)資料,需要的朋友可以參考下2016-04-04
從0構(gòu)建Oauth2Server服務(wù)之Refreshing-access-tokens
這篇文章主要為大家介紹了從0構(gòu)建Oauth2Server服務(wù)之Refreshing-access-tokens刷新令牌示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
使用SpringBoot讀取Windows共享文件的代碼示例
在現(xiàn)代企業(yè)環(huán)境中,文件共享是一個(gè)常見(jiàn)的需求,Windows共享文件夾(SMB/CIFS協(xié)議)因其易用性和廣泛的兼容性,成為了許多企業(yè)的首選,在Java應(yīng)用中,尤其是使用Spring Boot框架時(shí),如何讀取Windows共享文件是一個(gè)值得探討的話題,本文介紹了使用SpringBoot讀取Windows共享文件2024-11-11

