返回

解决Spring Boot MySQL驱动加载失败:Failed to load driver class

mysql

解决 Spring Boot 报错:Failed to load driver class com.mysql.jdbc.Driver

跑 Spring Boot 项目时,碰到了一个挺常见的错误,尤其是在配置多个数据源或者切换数据库环境的时候。这次是想让项目支持 H2 内存数据库和 MySQL 两种模式,H2 跑得好好的,一切换到 MySQL,应用就启动失败了,控制台直接甩给我一个 APPLICATION FAILED TO START,核心报错信息是这样的:

Description:

Failed to bind properties under '' to com.zaxxer.hikari.HikariDataSource:

    Property: driverclassname
    Value: com.mysql.jdbc.Driver;
    Origin: "driverClassName" from property source "source"
    Reason: Failed to load driver class com.mysql.jdbc.Driver; in either of HikariConfig class loader or Thread context classloader

Action:

Update your application's configuration

这个错误信息 Failed to load driver class com.mysql.jdbc.Driver; 说得很明白,就是应用程序(具体来说是 Hikari 连接池)在初始化数据源时,没能在类加载器(ClassLoader)里找到你指定的那个 MySQL 驱动类 com.mysql.jdbc.Driver;

就算你试了各种网上找的办法,比如删 .m2 仓库、重新导入依赖、Maven clean, compile, install 一条龙,甚至确认了 pom.xml 里确实加了 mysql-connector-java 依赖,问题还是没解决,确实会让人有点懵。

原因分析

为什么会找不到这个驱动类呢?明明依赖加了啊!别急,原因可能藏在几个地方:

  1. 驱动类名写错了 :这是最常见也最容易忽略的。类名是大小写敏感的,多一个字母少一个字母,甚至多一个标点符号都不行。
  2. 依赖没加对或版本有问题 :虽然 pom.xml 里写了 mysql-connector-java 依赖,但它的 <scope> 设置可能不合适(虽然 runtime 通常是对的),或者有版本冲突导致实际运行时这个 JAR 包没被包含进来。
  3. 使用的驱动类名与实际驱动版本不匹配 :MySQL Connector/J 驱动在不同版本,它的主驱动类名是会变的。老的版本(比如 5.x)用 com.mysql.jdbc.Driver,而新的版本(比如 6.x 及以后,尤其是 8.x)推荐用 com.mysql.cj.jdbc.Driver。你配置里写的类名必须和你引入的 mysql-connector-java 版本能对应上。
  4. Maven Profile 配置或激活问题 :使用了 Maven Profile 来管理不同环境的配置,需要确保激活 MySQL 对应的 Profile 时,相关的配置(包括 application-local_mysql.properties)能被正确加载。
  5. 自定义 DataSource 配置代码干扰 :项目里用了自定义的 DatasourceConfig.java 来创建 DataSource Bean。虽然这提供了灵活性,但也可能因为代码逻辑问题,没有正确处理驱动类的加载,或者覆盖了 Spring Boot 的一些自动配置优化。
  6. IDE 或构建工具缓存 :虽然清理了 Maven 缓存,但有时候 IDE(如 IntelliJ IDEA, Eclipse)自身的缓存或者编译输出目录没清理干净,也可能导致旧代码或配置生效。

结合错误信息里那个带分号的 Value: com.mysql.jdbc.Driver;,第一个原因——驱动类名写错了 ——嫌疑最大!

解决方案

接下来,我们一步步排查,看看怎么把这个问题搞定。

1. 检查并修正 Driver Class Name

这是最应该先检查的地方,尤其是看到错误信息里那个奇怪的分号。

  • 原理 : Java 的类加载器是根据你提供的完整类名(包名+类名)去找 .class 文件的。多一个字符少一个字符,都会导致 ClassNotFoundException 或类似的加载失败。

  • 操作步骤 :

    1. 打开 application-local_mysql.properties 文件。
    2. 找到 domain.datasource.driver-class 这一行。
    3. 仔细检查值 com.mysql.jdbc.Driver;看到末尾那个分号了吗?删掉它! 正确的类名不应该包含分号。
    4. 修改后的配置应该是:
      domain.datasource.driver-class=com.mysql.jdbc.Driver
      
  • 进阶提示与版本 :

    • 如果你 pom.xml 文件里引入的 mysql-connector-java 依赖是 6.x 或更高版本(特别是 8.x) ,那么推荐(有时是必须)使用新的驱动类名:com.mysql.cj.jdbc.Driver
    • 检查你的 mysql-connector-java 版本。可以在 pom.xml 里看,或者通过 Maven 依赖树(mvn dependency:tree)确认最终生效的版本。
    • 如果确认用了新版本驱动,就把 application-local_mysql.properties 里的 driver-class 修改为:
      domain.datasource.driver-class=com.mysql.cj.jdbc.Driver
      
    • 通常,如果你使用的是较新版本的 Spring Boot (比如 2.x 或更高) 配合 mysql-connector-java 8.x,Spring Boot 能够根据 JDBC URL (jdbc:mysql://...) 自动推断出正确的驱动类名 (com.mysql.cj.jdbc.Driver),甚至不需要显式配置 driver-class-namedriverClassName。但由于你这里用了自定义属性 domain.datasource.driver-class 并在 DatasourceConfig 里手动设置,所以这个值的准确性就非常关键了。

2. 确认 MySQL Connector/J 依赖

虽然感觉已经加了,但再次确认总没错,特别是检查生效的版本和范围。

  • 原理 : com.mysql.jdbc.Drivercom.mysql.cj.jdbc.Driver 这个类是包含在 mysql-connector-java 这个 JAR 包里的。程序运行时,这个 JAR 包必须在应用的 Classpath 中,类加载器才能找到它。

  • 操作步骤 :

    1. 检查 pom.xml : 确保 <dependency> 部分确实包含了 mysql-connector-java。给出的 pom.xml 里已经有了:
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <scope>runtime</scope>
      </dependency>
      
      这里的 <scope>runtime</scope> 表示这个依赖只在运行时和测试时需要,编译时不需要。对于 JDBC 驱动来说,这个 scope 通常是合适的。
    2. 确认依赖版本 : 你可以通过 pom.xml<dependencyManagement> 部分(如果父 POM 或项目中有定义)或者直接在 <dependency> 里指定 <version> 来确定版本。如果没有明确指定,它会继承自父 POM (spring-boot-starter-parent) 管理的版本,或者你需要通过 Maven 命令查看实际解析的版本。
    3. 使用 Maven Helper 插件 (IDE) : 如果用 IntelliJ IDEA,可以安装 Maven Helper 插件,方便地查看依赖树,检查是否有冲突,以及最终生效的版本。
    4. 使用 Maven 命令 : 在项目根目录下打开终端或命令行,运行:
      mvn dependency:tree
      
      这个命令会打印出项目的依赖树,搜索 mysql-connector-java,看看它是否在列表里,以及它的 scope 和最终确定的版本是什么。确认没有被 exclusion 掉,也没有版本冲突导致使用了预期之外的版本。
  • 安全建议 : 尽量使用稳定且较新的 mysql-connector-java 版本,旧版本可能存在安全漏洞或与新版 MySQL 服务器不兼容。

3. 审视并可能简化 DataSource 配置

你的项目使用了自定义的 DatasourceConfig.java 来创建 DataSource Bean。虽然功能上没问题,但有时过度配置反而会引入问题,或者错失 Spring Boot 自动配置带来的便利。

  • 原理 : Spring Boot 在检测到 Classpath 上有相应的数据库驱动和 spring-boot-starter-data-jpaspring-boot-starter-jdbc 时,会尝试自动配置一个 DataSource Bean。它通常会读取 application.propertiesapplication.yml 文件中以 spring.datasource. 开头的标准属性。HikariCP 是 Spring Boot 2.x 默认的连接池实现,它也能基于 JDBC URL 智能推断出 driver class。
  • 检查点与建议 :
    1. 手动设置 Driver Class 的必要性 : 在你的 DatasourceConfig 中,你显式调用了 .driverClassName(driverClass)。正如前面提到的,对于很多现代 JDBC 驱动和连接池(包括 HikariCP),只要提供了正确的 JDBC URL (domain.datasource.url) 并且驱动 JAR 在 classpath 上,连接池可以自动检测到驱动类,不一定需要 手动设置 driverClassName
    2. 尝试移除手动设置 : 你可以试试修改 DatasourceConfig.java,在创建 MySQL 的 DataSource 时,去掉 .driverClassName(driverClass) 这一行,以及对应的 @Value("${domain.datasource.driver-class}") private String driverClass; 注入。让 HikariCP 自己去根据 URL (jdbc:mysql://...) 推断。修改后的 dataSource() 方法 MySQL 分支可能看起来像这样:
      if (type.equals("MYSQL")) {
          return DataSourceBuilder
                  .create()
                  .username(username)
                  .password(password)
                  .url(url)
                  //.driverClassName(driverClass) // 尝试注释掉或删除这行
                  .build();
      } 
      // ... H2部分保持不变
      
      前提是 :你的 mysql-connector-java 驱动版本与 HikariCP/Spring Boot 兼容,且驱动 JAR 确实在运行时 Classpath 中。
    3. 考虑使用标准 Spring Boot 属性 : 长远来看,如果不是有特别复杂的定制需求,直接使用 Spring Boot 的标准数据源属性 (spring.datasource.url, spring.datasource.username, spring.datasource.password, spring.datasource.driver-class-name) 通常更简单、更健壮,也能更好地利用 Spring Boot 的自动配置和 Actuator 的健康检查等特性。不过,这需要修改你的属性文件命名和 DatasourceConfig 的逻辑(甚至可能完全移除 DatasourceConfig,让 Spring Boot 自动配置)。

4. 检查 Maven Profile 激活状态

确保当你想要连接 MySQL 时,local_mysql 这个 profile 被正确激活了,这样 application-local_mysql.properties 文件才会被加载。

  • 原理 : Spring Boot 会根据激活的 Profile(比如 local_mysql)加载对应的 application-{profile}.properties 文件,其中的配置会覆盖 application.properties 里的同名配置。如果 Profile 没激活对,那 MySQL 的配置自然就没用上。
  • 操作步骤 :
    1. 如何激活 Profile :
      • 命令行 : 运行 JAR 包时,使用 -Dspring.profiles.active=local_mysql 参数:
        java -jar target/my-project-0.0.1-SNAPSHOT.jar -Dspring.profiles.active=local_mysql
        
      • IDE 运行配置 (以 IntelliJ IDEA 为例) : 在 Run/Debug Configurations 里,找到你的 Spring Boot 应用配置,在 Environment -> Active profiles 字段填入 local_mysql
      • Maven 插件 : 如果通过 spring-boot-maven-plugin 运行,可以在配置中指定 profile 或通过命令行参数 -Dspring-boot.run.profiles=local_mysql
      • 操作系统环境变量 : 设置 SPRING_PROFILES_ACTIVE=local_mysql
    2. 确认激活日志 : Spring Boot 启动时,通常会在日志中打印出当前激活的 Profile。留意类似 The following profiles are active: local_mysql 的日志信息。如果没有看到 local_mysql,说明 Profile 没有成功激活。

5. 清理构建缓存与重启

最后,如果以上都没解决问题,可以试试更彻底的清理。

  • 原理 : 有时旧的编译结果或缓存文件会干扰程序的正常运行。
  • 操作步骤 :
    1. Maven 清理 :
      mvn clean
      
      这会删除 target 目录。
    2. IDE 清理 :
      • IntelliJ IDEA : Build -> Rebuild Project。还可以尝试 File -> Invalidate Caches / Restart... -> 选择 Invalidate and Restart
      • Eclipse : Project -> Clean... -> 选择你的项目。
    3. 删除 .m2 目录下相关依赖 (谨慎操作) : 你之前提过尝试了删除 .m2,如果再次尝试,确保你知道自己在做什么。可以只删除 ~/.m2/repository/mysql/mysql-connector-java/ 目录,然后让 Maven 重新下载。
    4. 重新构建和运行 : 执行 mvn clean install (或者至少 mvn clean package),然后用正确的方式激活 local_mysql profile 来启动你的应用。

通过以上步骤,最可能的原因——那个多余的分号——应该能被找到并修正。同时,检查驱动版本和依赖配置、理解 Profile 机制也很重要,能帮你避免未来的类似问题。优先处理第一点(修正驱动名),如果还不行,再依次排查后面的点。