You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala项目sbt-assembly导致MariaDB驱动连接MySQL 8失败求助

问题描述

我正在将Scala 2.12项目中的MySQL Connector/J替换为MariaDB Connector/J 2.7.12。原本以为是MariaDB驱动存在bug,经过一周排查发现,实际问题是sbt-assembly的合并逻辑替换了相关库,导致MariaDB驱动连接MySQL 8时抛出错误。

报错信息

java.sql.SQLNonTransientConnectionException: Could not connect to address=(host=192.168.240.7)(port=3306)(type=master) : Client does not support authentication protocol requested by server. plugin type was = 'caching_sha2_password'
at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.createException(ExceptionFactory.java:73)

我确认不是驱动本身的问题:在一个小型测试应用中,使用相同的驱动、Scala和Java版本,移除build.sbt中的合并逻辑并手动排除重复依赖后可以正常运行。但实际应用依赖的库更多,没法这么简单处理。

请问是否有办法确保sbt-assembly优先选用MariaDB Connector/J jar中的类?如果没有,有没有包含该驱动的可用build.sbt示例?

已尝试操作

  • 替换库;
  • 尝试不同版本的MariaDB Connector/J;
  • 使用mysql_native_password认证插件时可以连接MySQL 8;
  • 可以连接MySQL 5.7服务器,但默认情况下无法连接MySQL 8服务器。

期望实现

用MariaDB驱动无缝替换MySQL驱动。

补充测试代码

Maria.scala

package com.test

import java.sql.Connection
import java.sql.DriverManager
import java.sql.SQLException
import org.mariadb.jdbc.Driver

object Maria {
  def main(args: Array[String]) = {
    var connection:Connection = null

    try {
      println("Start...")
      // DriverManager.registerDriver(new org.mariadb.jdbc.Driver())
      Class.forName("org.mariadb.jdbc.Driver")
      println("Registered driver")
      connection = DriverManager.getConnection(
        "jdbc:mariadb://maria-mysql2-1:3306/test?allowPublicKeyRetrieval=true", 
        "root", "password")
        
      println(s"Connection valid: ${connection.isValid(5)}")

      val statement = connection.createStatement()
      val resultSet = statement.executeQuery("SELECT id, name FROM test")
      while ( resultSet.next() ) {
        val id = resultSet.getInt("id")
        val name = resultSet.getString("name")
        println(s"> ${id}. ${name}")
      }
    } catch {
      case e: Exception => {
        println(e.printStackTrace)
      }
    } finally {
      println("Close...")
      connection.close()
      println(s"Connection valid: ${connection.isValid(5)}")
    }
  }
}

可正常运行的build.sbt

version := "0.1.0-SNAPSHOT"
organization := "com.test"
scalaVersion := "2.12.19"
name := "Maria"

Compile / mainClass := Some("com.test.Maria")
assembly / mainClass := Some("com.test.Maria")
assembly / assemblyJarName := s"${name.value}-${version.value}.jar"
libraryDependencies ++= Seq(
  "org.scala-lang.modules" %% "scala-parser-combinators" % "2.3.0",
  "org.mariadb.jdbc" % "mariadb-java-client" % "2.7.12"
)

excludeDependencies ++= Seq(
  ExclusionRule("org.slf4j", "slf4j-api"),
  ExclusionRule("org.slf4j", "jcl-over-slf4j")
)

注:若移除excludeDependencies部分并替换为标准合并逻辑,就会出现连接错误。


解决方案

1. 配置sbt-assembly优先选用MariaDB的类

核心是通过assemblyMergeStrategy指定MariaDB相关包的优先级,确保合并时保留MariaDB驱动的类,覆盖其他依赖中可能存在的冲突类(比如旧MySQL驱动的残留类)。

在build.sbt中添加以下合并策略:

assemblyMergeStrategy in assembly := {
  // 优先保留MariaDB驱动的所有类
  case PathList("org", "mariadb", xs @ _*) => MergeStrategy.first
  // 处理JDBC驱动服务配置文件,避免合并冲突
  case "META-INF/services/java.sql.Driver" => MergeStrategy.filterDistinctLines
  // 其他默认合并策略
  case x =>
    val oldStrategy = (assemblyMergeStrategy in assembly).value
    oldStrategy(x)
}

2. 完整的build.sbt示例

结合依赖排除和合并策略,确保MariaDB驱动正常工作:

version := "0.1.0-SNAPSHOT"
organization := "com.test"
scalaVersion := "2.12.19"
name := "Maria"

Compile / mainClass := Some("com.test.Maria")
assembly / mainClass := Some("com.test.Maria")
assembly / assemblyJarName := s"${name.value}-${version.value}.jar"

libraryDependencies ++= Seq(
  "org.scala-lang.modules" %% "scala-parser-combinators" % "2.3.0",
  // 引入MariaDB驱动,同时排除可能冲突的依赖
  "org.mariadb.jdbc" % "mariadb-java-client" % "2.7.12" excludeAll(
    ExclusionRule("org.slf4j", "slf4j-api"),
    ExclusionRule("org.slf4j", "jcl-over-slf4j")
  )
)

// 配置assembly合并策略,优先保留MariaDB的类
assemblyMergeStrategy in assembly := {
  case PathList("org", "mariadb", xs @ _*) => MergeStrategy.first
  case "META-INF/services/java.sql.Driver" => MergeStrategy.filterDistinctLines
  // 处理其他常见冲突文件
  case "META-INF/LICENSE" => MergeStrategy.first
  case "META-INF/NOTICE" => MergeStrategy.first
  case x =>
    val oldStrategy = (assemblyMergeStrategy in assembly).value
    oldStrategy(x)
}

3. 额外注意事项

  • 用sbt dependencyTree命令检查项目依赖,确保没有残留的MySQL Connector/J依赖,如有则手动排除;
  • JDBC URL必须使用jdbc:mariadb://前缀,不要混用jdbc:mysql://;
  • 连接参数allowPublicKeyRetrieval=true要保留,这是MySQL 8使用caching_sha2_password认证时的必要参数。

内容的提问来源于stack exchange,提问作者AndrewBurton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 21:15:54