版权声明:本文为博主原创文章,转载需标明出处哦 ^-^。 https://blog.csdn.net/qq_33101675/article/details/86506495
线上环境凌晨5分有个定时任务执行了,但是执行过程中有报错,导致数据全部回滚,报错信息如下:
### Cause: java.sql.SQLException: connection holder is null
; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; connection holder is null; nested exception is java.sql.SQLException: connection holder is null
翻开 Druid的源码找找看
public int removeAbandoned() {
int removeCount = 0;
long currrentNanos = System.nanoTime();
List<DruidPooledConnection> abandonedList = new ArrayList();
this.activeConnectionLock.lock();
Iterator iter;
DruidPooledConnection pooledConnection;
try {
iter = this.activeConnections.keySet().iterator();
while(iter.hasNext()) {
pooledConnection = (DruidPooledConnection)iter.next();
if (!pooledConnection.isRunning()) {
long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / 1000000L;
if (timeMillis >= this.removeAbandonedTimeoutMillis) {
iter.remove();
pooledConnection.setTraceEnable(false);
abandonedList.add(pooledConnection);
}
}
}
} finally {
this.activeConnectionLock.unlock();
}
if (abandonedList.size() > 0) {
iter = abandonedList.iterator();
while(true) {
do {
while(true) {
if (!iter.hasNext()) {
return removeCount;
}
pooledConnection = (DruidPooledConnection)iter.next();
ReentrantLock lock = pooledConnection.lock;
lock.lock();
try {
if (pooledConnection.isDisable()) {
continue;
}
break;
} finally {
lock.unlock();
}
}
JdbcUtils.close(pooledConnection);
pooledConnection.abandond();
++this.removeAbandonedCount;
++removeCount;
} while(!this.isLogAbandoned());
StringBuilder buf = new StringBuilder();
buf.append("abandon connection, owner thread: ");
buf.append(pooledConnection.getOwnerThread().getName());
buf.append(", connected at : ");
buf.append(pooledConnection.getConnectedTimeMillis());
buf.append(", open stackTrace\n");
StackTraceElement[] trace = pooledConnection.getConnectStackTrace();
int i;
for(i = 0; i < trace.length; ++i) {
buf.append("\tat ");
buf.append(trace[i].toString());
buf.append("\n");
}
buf.append("ownerThread current state is " + pooledConnection.getOwnerThread().getState() + ", current stackTrace\n");
trace = pooledConnection.getOwnerThread().getStackTrace();
for(i = 0; i < trace.length; ++i) {
buf.append("\tat ");
buf.append(trace[i].toString());
buf.append("\n");
}
LOG.error(buf.toString());
}
} else {
return removeCount;
}
}
上面的代码核心就是
目前我的配置是,
jdbc.removeAbandoned=true
jdbc.removeAbandonedTimeout=180
表示一个没在使用的连接的存活时间超过了3分钟,就会回收掉;我们这个定时任务是被包含在一个大事务里,所以可能会发生这种问题。
解决方案:
1、改成
jdbc.removeAbandoned=true
jdbc.removeAbandonedTimeout=1800
2、把事务变得尽可能小