分析一下 Druid 中对于异常情况的一些处理。
一、Druid 中自定义了哪些异常?
pool 包下比较关键的一些异常有:
- DataSourceClosedException
- DataSourceDisableException
- DataSourceNotAvailableException
- GetConnectionTimeoutException
当获取连接时,如果数据源是处于关闭状态,那么就会抛DataSourceClosedException
异常,当数据源不可用时,就会抛 DataSourceDisableException
异常
private DruidPooledConnection getConnectionInternal(long maxWait) throws SQLException {
if (closed) { // 数据源是关闭状态
connectErrorCountUpdater.incrementAndGet(this);
// 抛 DataSourceClosedException
throw new DataSourceClosedException("dataSource already closed at " + new Date(closeTimeMillis));
}
if (!enable) { // 数据源不可用
connectErrorCountUpdater.incrementAndGet(this);
if (disableException != null) {
throw disableException;
}
// 抛 DataSourceDisableException
throw new DataSourceDisableException();
}
...
}
从 connections[]数组中获取连接 时,连续失败,便会抛出 DataSourceNotAvailableException
异常
if (maxWait > 0) {
holder = pollLast(nanos);
} else {
// 从connections[]数组中获取连接
holder = takeLast();
}
...
// takeLast():
if (failFast && isFailContinuous()) {
throw new DataSourceNotAvailableException(createError);
}
当获取连接超过指定等待时间,便会抛出 GetConnectionTimeoutException
异常:
if (createError != null) {
throw new GetConnectionTimeoutException(errorMessage, createError);
} else {
throw new GetConnectionTimeoutException(errorMessage);
}
二、ExceptionSorter
ExceptionSorter 接口
/**
* An interface to allow for exception evaluation.
*/
public interface ExceptionSorter {
/**
* 判断异常是否致命
* Returns true or false whether or not the exception is fatal.
*
* @param e the exception
* @return true or false if the exception is fatal.
*/
boolean isExceptionFatal(SQLException e);
void configFromProperties(Properties properties);
}
很多异常分拣类都是实现了 ExceptionSorter 这个接口,如图:
ExceptionSorter#isExceptionFatal() 方法用来判断异常是否致命,如果致命那么需要进行处理,拿 DB2ExceptionSorter 举例,如果是 isExceptionFatal() 方法判断异常是致命的,那么便会进行处理:
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);
}
}
handleFatalError() 方法里详细处理流程待分析。