Slick 3.2插入H2数据库无数据写入问题求助
嘿,我来帮你排查这个Slick 3.2单元测试数据没插入H2的问题!这种情况大概率是几个常见的“坑”导致的,咱们一个个捋:
1. 测试框架的事务自动回滚
很多Scala测试框架(比如ScalaTest的DatabaseForEach)默认会在测试结束后自动回滚事务,目的是避免测试间的数据污染。如果你的测试类用了这类自动回滚配置,插入的数据会在测试结束后被撤销,自然查不到。
- 解决办法:如果需要验证插入后的数据,可以手动在测试里提交事务,或者调整测试配置关闭自动回滚。比如在Slick中,你可以把插入操作包装在显式的事务提交里:
也可以换用支持保留数据的测试扩展,比如ScalaTest的db.run(DBIO.seq( Question returning Question.map(_.id) += QuestionRow(0l, UUID.randomUUID().toString, title, body, authorUuid.toString), DBIO.succeed(()) ).transactionally)withCleanInsert(适合需要清空表再插入的场景)。
2. H2内存模式的配置问题
H2的内存数据库默认是关闭最后一个连接就销毁数据,如果你的测试中连接池的连接被回收,或者多个测试用了同一个内存库但没加参数,数据就会直接消失。
- 检查你的数据库URL是不是类似这样:
jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSEDB_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
相关产品推荐
相关产品推荐

