[alibaba/druid]服务运行一段时间后 死循环报错 create connection SQLException:Locale not recognized

2025-11-05 900 views
7
oracle12C ,数据库最大连接数200,druid版本1.1.10,1.1.21 均有这个报错,监控服务显示调用链中显示获取连接池连接耗时占比99%,方法名com.alibaba.druid.pool.DruidDataSource.getConnection,而且连接池中的连接数利用率很低,最大连接数20 实际利用率峰值也就40%-50%,服务到-数据库的网络也没有问题,请大佬帮忙看下,应该从哪些方面排查,获取连接池中连接慢的问题

配置信息如下: initial-size: 5 min-idle: 5 max-active: 20 max-wait: 60000 use-unfair-lock: true test-while-idle: true time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 90000 test-on-borrow: false test-on-return: false pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 监控页面显示 从连接池获取连接时间长,等待获取连接时间长 MaxWait 60000 LogDifferentThread true UseUnfairLock false 累计总次数 71 等待总时长 4020028 池中连接数 0

服务异常时,服务器cpu使用率正常,内存使用率也正常 异常信息如下 死循环,一直报错,这个时候监控页面可用,其他请求不可用。 [ERROR] 2023-09-05 09:07:53.650 [Druid-ConnectionPool-Create-1099766787] [,,,] c.alibaba.druid.pool.DruidDataSource - create connection SQLException, url: jdbc:oracle:thin:@xxx.xxx.xxxx:1521/xxxx, errorCode 17176, state 99999 java.sql.SQLException: Locale not recognized at oracle.jdbc.driver.T4CTTIoauthenticate.setSessionFields(T4CTTIoauthenticate.java:990) at oracle.jdbc.driver.T4CTTIoauthenticate.(T4CTTIoauthenticate.java:235) at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:370) at oracle.jdbc.driver.PhysicalConnection.(PhysicalConnection.java:546) at oracle.jdbc.driver.T4CConnection.(T4CConnection.java:236) at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32) at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:521) at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:156) at com.alibaba.druid.filter.FilterAdapter.connection_connect(FilterAdapter.java:787) at com.alibaba.druid.filter.FilterEventAdapter.connection_connect(FilterEventAdapter.java:38) at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:150) at com.alibaba.druid.filter.stat.StatFilter.connection_connect(StatFilter.java:218) at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:150) at com.alibaba.druid.filter.FilterAdapter.connection_connect(FilterAdapter.java:787) at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:150) at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1646) at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1710) at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2753)

回答

4

这个是你连Oracle的问题,网上搜索看下Locale的设置是不是被某处代码设置成null了。 这个问题与druid无关。

https://www.bing.com/search?q=java.sql.SQLException%3A+Locale+not+recognized&form=QBLH&sp=-1&lq=0&pq=java.sql.sqlexception%3A+locale+not+recognized&sc=7-44&qs=n&sk=&cvid=B732972024A141B29CD0D26ABE5C4546&ghsh=0&ghacc=0&ghpl=

8

检查了linux服务器语言环境、JAVA运行语言环境、ORACLE语言环境、已经去掉了原先的JAVA运行JVM参数语言环境设置、依然会出现此报错信息,除外发现了新的报错信息。

5

新的报错日志如下: com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 5000, active 0, maxActive 30, creating 0, createErrorCount 13047 at com.alibaba.druid.pool.DruidDataSource.getConnectionInternal(DruidDataSource.java:1773) at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1427) at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:5059) at com.alibaba.druid.filter.logging.LogFilter.dataSource_getConnection(LogFilter.java:917) at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:5055) at com.alibaba.druid.filter.stat.StatFilter.dataSource_getConnection(StatFilter.java:726) at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:5055) at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1405) at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1397) at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:100) at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:204) at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373) at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:430) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:276) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ... ...//省略的栈帧 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

0

开启了如下配置、但是在日志输出中没有查到 泄漏连接的信息。请问大佬,还可以从哪个方向,查询应用中导致连接泄漏的方法。 对泄漏的连接 自动关闭 打开removeAbandoned功能 property name="removeAbandoned" value="true" property name="removeAbandonedTimeout" value="60" 关闭abanded连接时输出错误日志 property name="logAbandoned" value="true"

8

使用最新版 1.2.19依赖,然后参考我的示例代码。自己实现filter,通过计数器和map去监控连接的创建和销毁。看下有啥连接没有及时释放或归还。


    static class DruidConnectionAliveCheckFilter extends FilterAdapter {
        ConcurrentHashMap<String, ConnectionStatInfo> statMap = new ConcurrentHashMap<>(512);

        public String dumpStatInfo() {
            StringBuilder sb = new StringBuilder();
            sb.append("当前存活连接数是").append(statMap.size()).append("\n");
            for (Map.Entry<String, ConnectionStatInfo> e : new TreeMap<>(statMap).entrySet()) {
                sb.append(e.getKey()).append("=").append(e.getValue()).append("\n");
            }
            return sb.toString();
        }

        Set<String> traceSet = new HashSet<>();
        @Override
        public DruidPooledConnection dataSource_getConnection(FilterChain chain, DruidDataSource dataSource, long maxWaitMillis) throws SQLException {
            DruidPooledConnection dpc = super.dataSource_getConnection(chain, dataSource, maxWaitMillis);
            ConnectionProxy connection = (ConnectionProxy) dpc.getConnectionHolder().getConnection();
            String traceLog=DruidDataSourceLogTest.toString(new Exception());
            //System.out.println(traceLog);
            if(!traceSet.contains(traceLog)){
                traceSet.add(traceLog);
                System.out.println("tracelog获取连接池连接dataSource_getConnection"+traceLog);
            }
            System.out.println(LocalDateTime.now()+"获取连接池连接dataSource_getConnection" + connection.getId()+"|"+connection);
            String key = dataSource.getDataSourceId() + "_" + connection.getId();
            ConnectionStatInfo statinfo = statMap.get(key);
            if (statinfo == null) {
                System.out.println("dataSource_getConnection不可能为null啊|" + key);
            } else {
                statinfo.getUsedCount().incrementAndGet();
                statinfo.setLastBorrowTimeMs(System.currentTimeMillis());
            }
            return dpc;
        }

        @Override
        public void dataSource_releaseConnection(FilterChain chain, DruidPooledConnection connection) throws SQLException {
            ConnectionProxy connectionTmp = (ConnectionProxy) connection.getConnectionHolder().getConnection();
            System.out.println(LocalDateTime.now()+"归还连接池连接dataSource_releaseConnection" + connectionTmp.getId()+"|"+connection);
            String traceLog=DruidDataSourceLogTest.toString(new Exception());
            //System.out.println(traceLog);
            if(!traceSet.contains(traceLog)){
                traceSet.add(traceLog);
                System.out.println("tracelog归还连接池连接dataSource_releaseConnection"+traceLog);
            }
            String key = connectionTmp.getDirectDataSource().getDataSourceId() + "_" + connectionTmp.getId();
            ConnectionStatInfo statinfo = statMap.get(key);
            if (statinfo == null) {
                System.out.println("dataSource_releaseConnection不可能为null啊|" + key);
            } else {
                statinfo.setLastReturnTimeMs(System.currentTimeMillis());
            }
            super.dataSource_releaseConnection(chain, connection);

        }

        @Override
        public ConnectionProxy connection_connect(FilterChain chain, Properties info) throws SQLException {
            ConnectionProxy connection = super.connection_connect(chain, info);
            System.out.println(LocalDateTime.now()+"获取物理连接connection_connect" + connection.getId()+"|"+connection);
            String traceLog=DruidDataSourceLogTest.toString(new Exception());
            //System.out.println(traceLog);
            if(!traceSet.contains(traceLog)){
                traceSet.add(traceLog);
                System.out.println("tracelog获取物理连接connection_connect"+traceLog);
            }
            String key = connection.getDirectDataSource().getDataSourceId() + "_" + connection.getId();
            if (statMap.get(key) == null) {
                ConnectionStatInfo statinfo = new ConnectionStatInfo();
                statinfo.setDatasourceId(connection.getDirectDataSource().getDataSourceId());
                statinfo.setConnectionId(connection.getId());
                statMap.put(key, statinfo);
            }
            return connection;
        }

        @Override
        public void connection_close(FilterChain chain, ConnectionProxy connection) throws SQLException {
            System.out.println(LocalDateTime.now()+"关闭物理连接connection_close" + connection.getId()+"|"+connection);
            String traceLog=DruidDataSourceLogTest.toString(new Exception());
            //System.out.println(traceLog);
            if(!traceSet.contains(traceLog)){
                traceSet.add(traceLog);
                System.out.println("tracelog关闭物理连接connection_close"+traceLog);
            }
            String key = connection.getDirectDataSource().getDataSourceId() + "_" + connection.getId();
            statMap.remove(key);
            super.connection_close(chain, connection);
        }

        static class ConnectionStatInfo {
            long datasourceId;
            long connectionId;
            AtomicInteger usedCount = new AtomicInteger();
            long lastBorrowTimeMs;
            long lastReturnTimeMs;

            public long getDatasourceId() {
                return datasourceId;
            }

            public void setDatasourceId(long datasourceId) {
                this.datasourceId = datasourceId;
            }

            public long getConnectionId() {
                return connectionId;
            }

            public void setConnectionId(long connectionId) {
                this.connectionId = connectionId;
            }

            public AtomicInteger getUsedCount() {
                return usedCount;
            }

            public long getLastBorrowTimeMs() {
                return lastBorrowTimeMs;
            }

            public void setLastBorrowTimeMs(long lastBorrowTimeMs) {
                this.lastBorrowTimeMs = lastBorrowTimeMs;
            }

            public long getLastReturnTimeMs() {
                return lastReturnTimeMs;
            }

            public void setLastReturnTimeMs(long lastReturnTimeMs) {
                this.lastReturnTimeMs = lastReturnTimeMs;
            }

            @Override
            public String toString() {
                StringBuilder builder = new StringBuilder();
                builder.append("ConnectionStatInfo [datasourceId=");
                builder.append(datasourceId);
                builder.append(", connectionId=");
                builder.append(connectionId);
                builder.append(", usedCount=");
                builder.append(usedCount);
                builder.append(", lastBorrowTimeMs=");
                builder.append(lastBorrowTimeMs);
                builder.append(", lastBorrowTimeStr=");
                builder.append(new java.sql.Timestamp(lastBorrowTimeMs));
                builder.append(", lastReturnTimeMs=");
                builder.append(lastReturnTimeMs);
                builder.append(", lastReturnTimeStr=");
                builder.append(new java.sql.Timestamp(lastReturnTimeMs));
                builder.append("]");
                return builder.toString();
            }

        }
    }
    /**
     * 把异常对象转成完整堆栈的字符串
     *
     * @param t
     * @return
     */
    public static String toString(Throwable t) {
        StringWriter sw = new StringWriter();
        try (PrintWriter pw = new PrintWriter(sw)) {
            t.printStackTrace(pw);
        }
        return sw.toString();
    }
2

感谢大佬,问题已经复现,是因为我的服务中有一个截取pdf第一页的功能 使用了pdf.spire.free插件。插件处理响应很慢,每当有并发请求这个接口的时候,会出现druid的报错