DruidDataSource support killWhenSocketReadTimeout

This commit is contained in:
wenshao
2017-06-13 19:04:49 +08:00
parent a6d8255031
commit 3b2acf03bc
5 changed files with 118 additions and 2 deletions
@@ -44,7 +44,7 @@ public final class DruidConnectionHolder {
private final static Log LOG = LogFactory.getLog(DruidConnectionHolder.class);
private final DruidAbstractDataSource dataSource;
protected final DruidAbstractDataSource dataSource;
private final long connectionId;
private final Connection conn;
private final List<ConnectionEventListener> connectionEventListeners = new CopyOnWriteArrayList<ConnectionEventListener>();
@@ -37,7 +37,6 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -173,6 +172,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
private volatile boolean keepAlive = false;
protected boolean killWhenSocketReadTimeout = false;
public DruidDataSource(){
this(false);
}
@@ -387,6 +388,20 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
}
}
{
Boolean value = getBoolean(properties, "druid.killWhenSocketReadTimeout");
if (value != null) {
setKillWhenSocketReadTimeout(value);
}
}
}
public boolean isKillWhenSocketReadTimeout() {
return killWhenSocketReadTimeout;
}
public void setKillWhenSocketReadTimeout(boolean killWhenSocketTimeOut) {
this.killWhenSocketReadTimeout = killWhenSocketTimeOut;
}
public boolean isUseGlobalDataSourceStat() {
@@ -17,7 +17,11 @@ package com.alibaba.druid.pool;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.druid.util.JdbcUtils;
import com.alibaba.druid.util.MySqlUtils;
import java.net.SocketTimeoutException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
@@ -61,10 +65,83 @@ public class DruidPooledStatement extends PoolableWrapper implements Statement {
}
protected SQLException checkException(Throwable error) throws SQLException {
handleScoketTimeout(error);
exceptionCount++;
return conn.handleException(error);
}
private void handleScoketTimeout(Throwable error) throws SQLException {
if (this.conn == null
|| this.conn.transactionInfo != null
|| this.conn.holder == null) {
return;
}
DruidDataSource dataSource = null;
if (this.conn.holder.dataSource instanceof DruidDataSource) {
dataSource = (DruidDataSource) this.conn.holder.dataSource;
}
if (dataSource == null) {
return;
}
if (!dataSource.killWhenSocketReadTimeout) {
return;
}
SQLException sqlException = null;
if (error instanceof SQLException) {
sqlException = (SQLException) error;
}
if (sqlException == null) {
return;
}
Throwable cause = error.getCause();
boolean socketReadTimeout = cause instanceof SocketTimeoutException
&& "Read timed out".equals(cause.getMessage());
if (!socketReadTimeout) {
return;
}
if (!JdbcConstants.MYSQL.equals(dataSource.dbType)) {
return;
}
String killQuery = MySqlUtils.buildKillQuerySql(this.conn.getConnection(), (SQLException) error);
if (killQuery == null) {
return;
}
DruidPooledConnection killQueryConn = null;
Statement killQueryStmt = null;
try {
killQueryConn = dataSource.getConnection(1000);
if (killQueryConn == null) {
return;
}
killQueryStmt = killQueryConn.createStatement();
killQueryStmt.execute(killQuery);
if (LOG.isDebugEnabled()) {
LOG.debug(killQuery + " success.");
}
} catch (Exception ex) {
LOG.warn(killQuery + " error.", ex);
} finally {
JdbcUtils.close(killQueryStmt);
JdbcUtils.close(killQueryConn);
}
}
public DruidPooledConnection getPoolableConnection() {
return conn;
}
@@ -15,8 +15,14 @@
*/
package com.alibaba.druid.util;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.mysql.jdbc.ConnectionImpl;
import com.mysql.jdbc.MySQLConnection;
import com.mysql.jdbc.MysqlIO;
import javax.sql.XAConnection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
@@ -87,4 +93,15 @@ public class MySqlUtils {
throw new SQLFeatureNotSupportedException();
}
public static String buildKillQuerySql(Connection connection, SQLException error) throws SQLException {
try {
ConnectionImpl connImpl = (ConnectionImpl) connection;
long threadId = connImpl.getId();
return "KILL QUERY " + threadId;
} catch (Exception e) {
// skip
}
return null;
}
}
@@ -0,0 +1,7 @@
package com.alibaba.druid.pool;
/**
* Created by wenshao on 13/06/2017.
*/
public class ExceptionSorterKillTest {
}