SQL state [null]; error code [0]; connection holder is null

版权声明:本文为博主原创文章,转载需标明出处哦 ^-^。 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、把事务变得尽可能小

猜你喜欢

转载自blog.csdn.net/qq_33101675/article/details/86506495