返回

数据库连接池提前初始化引发的异常及解决办法

后端

数据库连接池提前初始化引发的异常

背景

我们线上一个项目在发版本时,经常会有部分实例无法正常启动的情况,特别是在没有进行灰度发布的场景下,基本上很难正常的启动成功,异常信息如下:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$HikariConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.IllegalStateException: driverClassName specified twice [com.mysql.jdbc.Driver, com.mysql.cj.jdbc.Driver]

问题分析

看日志可以很容易看出来,启动异常的原因是hikaricp连接池初始化异常,经过排查,是因为同时引入了两个mysql驱动引起的,于是删除一个驱动,问题解决

解决办法

将代码中的mysql-connector-java-5.1.46.jar文件删除,再重启项目,问题解决。

以下是本次异常的一些思考和总结:

  1. hikari数据库连接池中,如果指定了连接池类名,那么在构建数据源时,就不会使用SpringBoot默认的配置,例如:spring.datasource.driver-class-name

  2. hikari在初始化连接池时,会先判断是否已经有数据源的连接池了,如果已经有的话就不会在创建,所以我们在自定义数据源时,千万不要忘记销毁连接池。

  3. hikari连接池默认在启动时不会进行预热,如果连接池中没有连接,那么第一次使用时,会比较慢,所以我们可以通过以下方式开启连接池的预热。

spring:
  datasource:
    hikari:
      connection-test-query: isValid
      minimum-idle: 5
      maximum-pool-size: 10
      idle-timeout: 30000
      max-lifetime: 1800000
  1. 如果使用了连接池的话,那么在做数据库操作时,一定要注意不要忘记关闭连接,否则会导致连接泄露。

总结

数据库连接池是提高数据库连接性能的重要工具,但是使用时需要注意一些细节,否则容易出现异常。

在使用hikari连接池时,如果指定了连接池类名,那么在构建数据源时,就不会使用SpringBoot默认的配置,所以我们在自定义数据源时,千万不要忘记销毁连接池。

hikari连接池默认在启动时不会进行预热,如果连接池中没有连接,那么第一次使用时,会比较慢,所以我们可以通过设置connection-test-query来开启连接池的预热。

如果使用了连接池的话,那么在做数据库操作时,一定要注意不要忘记关闭连接,否则会导致连接泄露。