使用Druid连接数据库报错

使用Druid进行连接数据库报错,实在不知道问题出在哪里,报错信息在第53行conn = ds.getConnection();

img

img

img

img

img

img


求解决

ds为空。
先不要调接口,看看程序初始化启动时DBManager类打印了什么错误

看这个地方报错信息是什么

img

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这篇博客: (二)Druid数据库连接池如何获取Connection原理和源码分析?中的 (1)获取连接方法getConnectionDirect()线程: 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:

    这里是Druid的三个核心线程的交互逻辑图
    在这里插入图片描述
    ⚠️这里是init();初始化在这一步:主要核心就是创建这几个线程

    createAndLogThread();  //打印日志线程其实就是统计监控信息
    createAndStartCreatorThread(); //创建连接的线程
    createAndStartDestroyThread(); //销毁连接的线程
    
    • 首先第一大步骤就是先去获取DruidPooledConnection,通过getConnectionInternal()方法

      • 进入到方法内:

        1. 先进行一个for死循环当createDirect = true时跳出循环,首次为false,所以下一步重要的就是创建ScheduledThreadPoolExecutor 对象,条件就是当:【poolingCount(池子中的值为0时) && 活跃的连接 < maxActive && createScheduler != null && createScheduler instanceof ScheduledThreadPoolExecutor】 , 然后ScheduledThreadPoolExecutor中的getQueue().size() > 0 时,把createDirect = true,然后继续往下走,
        2. 然后通过我们设置的setMaxWait 时间进行判断,如果MaxWait > 0 ,就会从LRU的队列中的尾部取出一个connection使用方法 pollLast(nanos); 否则走takeLast();
        3. 如果DruidConnectionHolder 不为null ,把【connection】活跃的ActiveCount++,然后跳出循环
        4. 此时的createDirect = true,所以会去创建一个物理连接 赋值给 DruidConnectionHolder对象
        PhysicalConnectionInfo pyConnInfo = DruidDataSource.this.createPhysicalConnection();
        holder = new DruidConnectionHolder(this, pyConnInfo);
        
        1. 然后加锁,判断 activeCount < maxActive ,如果为True就把活跃的Connection连接进行➕1,跳出循环,如果 activeCount > maxActive,则需要丢弃创建好的这个创建好的物理连接
        JdbcUtils.close(pyConnInfo.getPhysicalConnection());
        
      • 如果成功继续走到下一步

      • 如果失败捕获住错误的话,就继续尝试获取DruidPooledConnection

    • 然后回到getConnectionDirect()方法中,走到第二个步骤中,先判断配置参数testOnBorrow是不是为True,然后去进行对连接进行校验,如果校验成功就继续往下走,

      boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
      if (!validate) {
          Connection realConnection = poolableConnection.conn;
          discardConnection(realConnection);
          continue;
      }
      
    • 如果配置参数testOnBorrow为True的话会先进行一次上面代码的校验如果testOnBorrow为False的话,并且 testWhileIdle参数为True的话,会再进行判断,如果【timeBetweenEvictionRunsMillis <= 0】直接使用 60s 进行填充

    • 继续走,如果当前连接的空闲时间idleMillis >= timeBetweenEvictionRunsMillis || idleMillis < 0】时,会继续进行校验当前连接的健康情况,和上面代码一样,如果校验不成功就会discard当前的Connection

    • 继续,然后判断配置参数removeAbandoned是不是为True,如果是就以当前连接poolableConnection 为Key,PRESENT作为Value放到activeConnections的Map集合中

      Map<DruidPooledConnection, Object> activeConnections                         = new IdentityHashMap<DruidPooledConnection, Object>();
    //这里是判断逻辑
                if (removeAbandoned) {
                    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
                    poolableConnection.connectStackTrace = stackTrace;
                    poolableConnection.setConnectedTimeNano();
                    poolableConnection.traceEnable = true;
    
                    activeConnectionLock.lock();
                    try {
                        activeConnections.put(poolableConnection, PRESENT);
                    } finally {
                        activeConnectionLock.unlock();
                    }
                }
    
    • 继续,如果配置的defaultAutoCommit参数是不是为False,如果为False,执行,poolableConnection.setAutoCommit(false);
    • 最后 getConnectionDirect(long maxWaitMillis)方法 返回DruidPooledConnection 对象 poolableConnection

    ⚠️这里补充一下第一大步的第2小步中的pollLast(nanos)takeLast(nanos)方法中如果没有从LRU队列中的尾部获取到Connection时,就会发送图中的notify信号,去通知创建连接的线程去创建连接**


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^