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

Slick 3.2插入H2数据库无数据写入问题求助

嘿,我来帮你排查这个Slick 3.2单元测试数据没插入H2的问题!这种情况大概率是几个常见的“坑”导致的,咱们一个个捋:

1. 测试框架的事务自动回滚

很多Scala测试框架(比如ScalaTest的DatabaseForEach)默认会在测试结束后自动回滚事务,目的是避免测试间的数据污染。如果你的测试类用了这类自动回滚配置,插入的数据会在测试结束后被撤销,自然查不到。

  • 解决办法:如果需要验证插入后的数据,可以手动在测试里提交事务,或者调整测试配置关闭自动回滚。比如在Slick中,你可以把插入操作包装在显式的事务提交里:
    db.run(DBIO.seq(
      Question returning Question.map(_.id) += QuestionRow(0l, UUID.randomUUID().toString, title, body, authorUuid.toString),
      DBIO.succeed(())
    ).transactionally)
    
    也可以换用支持保留数据的测试扩展,比如ScalaTest的withCleanInsert(适合需要清空表再插入的场景)。

2. H2内存模式的配置问题

H2的内存数据库默认是关闭最后一个连接就销毁数据,如果你的测试中连接池的连接被回收,或者多个测试用了同一个内存库但没加参数,数据就会直接消失。

  • 检查你的数据库URL是不是类似这样:
    jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
    
    DB_CLOSE_DELAY=-1会让H2在最后一个连接关闭后仍保留数据,DB_CLOSE_ON_EXIT=FALSE避免JVM退出时销毁数据库,这俩参数对内存模式的测试至关重要。

3. 没等待异步操作完成

Slick的db.run返回的是Future,如果你的测试没等这个Future完成就结束了,插入操作可能还没实际执行到数据库里。

  • 解决办法:要么用异步测试套件(比如ScalaTest的AsyncFlatSpec)让测试自动等待Future完成,要么手动阻塞等待:
    import scala.concurrent.Await
    import scala.concurrent.duration.Duration
    
    val insertResult = Await.result(dao.createQuestion("Test", "Content", UUID.randomUUID()), Duration.Inf)
    
    手动阻塞适合简单测试,异步套件会更优雅。

4. 数据库实例不统一

检查你的DAO里使用的db实例,和测试中用来查询验证数据的db是不是同一个对象。要是不小心初始化了两个不同的Database实例,插入操作在一个库执行,查询却查另一个库,肯定看不到数据。

5. 主键定义的小细节

看你的插入代码,你手动把id设为0l,如果你的Question表定义里id是自增主键(O.AutoInc),Slick会自动忽略这个0生成正确的自增ID,这本身没问题,但还是确认下你的表定义是不是正确:

class Question(tag: Tag) extends Table[QuestionRow](tag, "QUESTION") {
  def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
  def uuid = column[String]("UUID")
  def title = column[String]("TITLE")
  def body = column[String]("BODY")
  def authorUuid = column[String]("AUTHOR_UUID")
  
  override def * = (id, uuid, title, body, authorUuid) <> (QuestionRow.tupled, QuestionRow.unapply)
}

如果id没加O.AutoInc,插入0可能会导致主键冲突或者数据没正确写入(不过这种情况一般会抛异常)。

最后给你一个简单的异步测试示例,确保操作都能正确执行并验证:

import org.scalatest.AsyncFlatSpec
import org.scalatest.matchers.should.Matchers
import scala.concurrent.Future
import java.util.UUID

class QuestionDaoSpec extends AsyncFlatSpec with Matchers {
  private val testDb = Database.forConfig("h2test") // 和DAO用同一个配置
  private val questionDao = new YourQuestionDao(testDb)

  "QuestionDao.createQuestion" should "successfully insert a question into H2" in {
    val authorId = UUID.randomUUID()
    val insertFuture = questionDao.createQuestion("Test Title", "Test Body Content", authorId)

    insertFuture.flatMap { insertedId =>
      // 插入后查询验证
      questionDao.questions.map { questions =>
        questions should have size 1
        val insertedQuestion = questions.head
        insertedQuestion.id shouldBe insertedId
        insertedQuestion.title shouldBe "Test Title"
        insertedQuestion.authorUuid shouldBe authorId.toString
      }
    }
  }

  override def afterAll(): Unit = {
    testDb.close() // 测试结束关闭数据库
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:31:10