预测试 SBT 任务:无法实例化 JDBC 驱动程序

Posted

技术标签:

【中文标题】预测试 SBT 任务:无法实例化 JDBC 驱动程序【英文标题】:Pre-test SBT task: Unable to instantiate JDBC driver 【发布时间】:2021-06-05 07:00:44 【问题描述】:

我在获取 SBT 任务 以使用 Flyway 运行迁移时遇到问题;运行任务时出现异常。有什么想法可以解决吗?

org.flywaydb.core.api.FlywayException: Unable to instance JDBC driver: org.postgresql.Driver => 检查jar文件是否存在

以下代码在我的 测试 (ScalaTest) 中运行 BeforeAll 时有效,但当我将其移至 SBT 任务时无效。

val flyway = Flyway
  .configure()
  .locations("filesystem:./**/resources/db/migrations/")
  .dataSource("jdbc:postgresql://localhost:5432/my_database", "my_user", "secret")
  .load()
      
flyway.clean()
flyway.migrate()

我的/build.sbt 文件如下所示:

import org.flywaydb.core.Flyway

lazy val migrate = taskKey[Unit]("Migrate database")

lazy val migrateTask = Def.task 
  println("Migrate")
  val flyway = Flyway
    .configure()
    .locations("filesystem:./**/resources/db/migrations/")
    .dataSource("jdbc:postgresql://localhost:5432/my_database", "my_user", "secret")
    .load()

  flyway.clean()
  flyway.migrate()


val IntegrationTest = config("integration") extend Test

lazy val integrationTestSettings = inConfig(IntegrationTest)(Defaults.testSettings) ++ List(
  IntegrationTest / fork := false,
  IntegrationTest / parallelExecution := false,
  IntegrationTest / sourceDirectory := baseDirectory.value / "src/test/integration",
  IntegrationTest / test := 
    (IntegrationTest / test) dependsOn migrateTask
  .value
)

lazy val root = Project(id = "hello", base = file("."))
  .configs(Configs.all: _*)
  .settings(
    integrationTestSettings,
    libraryDependencies += "org.scalatest" %% "scalatest" % "3.1.4",
  )

而我的/project/build.sbt 看起来像这样:

libraryDependencies ++= List(
  "org.flywaydb"    % "flyway-core" % "7.6.0",
  "org.postgresql"  % "postgresql"  % "42.2.19",
)

我使用的版本是:

SBT:1.4.5 斯卡拉:2.13.4 飞行路线:7.6.0

有没有人知道我为什么会收到这个错误,以及如何解决它?

任何帮助将不胜感激。谢谢:)

【问题讨论】:

【参考方案1】:

在 Flyway 存储库上搜索,错误消息来自这里 - https://github.com/flyway/flyway/blob/9033185ab8bfa56b0dae9136c04763cdccc50081/flyway-core/src/main/java/org/flywaydb/core/internal/jdbc/DriverDataSource.java#L165-L182 它正在尝试从类加载器加载数据库驱动程序。这些 ClassLoader 技术有时会与 sbt 设置分层 ClassLoader 以运行 sbt 本身发生冲突。这是我对正在发生的事情的猜测。

我们如何解决这个问题?

你说运行它作为测试的一部分是有效的,所以也许你可以为此创建一个子项目?

ThisBuild / scalaVersion := "2.13.4"
lazy val migrate = taskKey[Unit]("Migrate database")

lazy val root = (project in file("."))
  .settings(
    name := "hello",
    migrate := (migrateProj / run).toTask("").value
  )

// utility project to run database migration
lazy val migrateProj = (project in file("migrate"))
  .settings(
    libraryDependencies ++= List(
      "org.flywaydb"    % "flyway-core" % "7.6.0",
      "org.postgresql"  % "postgresql"  % "42.2.19",
    ),
    Compile / run / fork := true,
    publish / skip := true,
  )

迁移/Migrate.scala

object Migrate extends App 
  println("migrate")

  // rest of the code here...

现在你可以运行了

sbt:flyway> migrate
[info] running (fork) Migrate
[info] migrate
[success] Total time: 4 s, completed Mar 6, 2021 9:03:07 PM

关于分层类加载器的详细信息

ClassLoader 技术有时会与 sbt 设置分层的 ClassLoader 以运行 sbt 本身发生冲突。 sbt-the-Bash-script 允许用户使用 project/build.properties 选择 sbt 版本,使用 build.sbt 选择 Scala 版本。这两者都使 sbt build 具有声明性和可重复性,通常是一件好事。但是使用 Scala 2.10 编写的 sbt 启动器如何启动使用 Scala 2.12 编写的 sbt 1.4.x,然后启动您的 Scala 2.13 应用程序?这些边界交叉中的每一个都是通过创建一个分层的 ClassLoader 来完成的,就像电影 Inception 一样。

【讨论】:

以上是关于预测试 SBT 任务:无法实例化 JDBC 驱动程序的主要内容,如果未能解决你的问题,请参考以下文章

Spark 无法从 SBT 找到 JDBC 驱动程序

如何在 SBT Scala 项目中使用 MySQL JDBC 驱动程序?

[XXX] 注册了JDBC驱动程 序 [oracle.jdbc.OracleDriver]

无法加载 JDBC 驱动程序。在

如何在 AWS EC2 实例上预安装 sbt(通过用户数据)?

无法获取 oracle 的驱动程序实例