You need to enable JavaScript to run this app. sbt项目中如何通过Slick加载jar包内的二进制SQLite数据库文件
优惠活动
大模型
产品
解决方案
定价
更多

sbt项目中如何通过Slick加载jar包内的二进制SQLite数据库文件

问题根因

SQLite JDBC 驱动仅能读取文件系统中真实存在的物理文件,你发布后获取的路径是JAR包内部资源的虚拟路径(带!标识),不属于操作系统可直接访问的文件路径,因此连接失败。

可行解决方案

推荐采用「运行时解压资源到临时目录」的方案,实现成本低、兼容性强,具体步骤如下:

步骤1:编写资源解压逻辑

在Sample.scala中新增将JAR内data.db复制到本地临时目录的代码,示例如下:

import java.io.{File, FileOutputStream}
import slick.jdbc.JdbcBackend.Database

// 临时目录存储路径,可根据需求调整为用户指定目录或应用缓存目录
private val tempDbPath = s"${System.getProperty("java.io.tmpdir")}/testkit_sample_data.db"
private val tempDbFile = new File(tempDbPath)

// 仅当临时文件不存在时复制,避免每次运行重复覆盖
if (!tempDbFile.exists()) {
  val resourceStream = getClass.getResourceAsStream("/data.db")
  require(resourceStream != null, "内置示例数据库文件不存在")
  val outputStream = new FileOutputStream(tempDbFile)
  // 流拷贝
  resourceStream.transferTo(outputStream)
  resourceStream.close()
  outputStream.close()
  // 可选:设置文件只读权限,避免其他用户篡改
  tempDbFile.setWritable(false)
}

// 用临时文件的真实路径创建连接
val conn = Database.forURL(s"jdbc:sqlite:$tempDbPath", prop = Map.empty[String, String])

注:以上代码中transferTo为Java 9+ API,若使用Java 8环境,可替换为手动字节流拷贝逻辑:

val buffer = new Array[Byte](1024)
var readLen: Int = 0
while ({readLen = resourceStream.read(buffer); readLen != -1}) {
  outputStream.write(buffer, 0, readLen)
}

可选优化点

  • 如果需要支持示例数据更新,可以在打包时给data.db加版本标识,运行时比对本地临时文件的版本,版本不一致时重新复制
  • 如果临时目录被系统清理,代码会自动重新生成文件,无需额外处理
  • 不需要额外修改sbt打包配置,原有资源打包逻辑保持不变即可

其他可选方案(不推荐)

可以使用支持ZIP/JAR内资源读取的扩展SQLite驱动,但兼容性差,不同操作系统、JDK版本容易出现适配问题,生产环境不建议使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 11:24:03