Slick事务中内部数据库操作未执行问题求助
问题排查与正确实现方案
我来帮你搞定这个问题!你遇到的情况是只有最开始的book插入生效,后面的bookModule和bookAssoc插入完全没执行,这是因为你的DBIO操作组合方式不对,没把内层的操作正确加入到执行流程里。咱们一步步拆解问题:
原代码的核心问题
第一段代码的问题
你这段代码里,action1.map返回的是一个嵌套的DBIO[DBIO[Seq[Seq[Unit]]]]——也就是说,最外层的DBIO执行后,只是生成了内层的DBIO操作,但并没有实际触发它们。map只是转换DBIO的结果值,不会把内层的DBIO合并到执行流程中,相当于你只是“定义了操作”,但没把它们放进要执行的事务里。
第二段for推导式的问题
你直接在DBIO的for推导式里遍历普通Scala集合(bookModules、userModRoles)是错误的。for推导式在DBIO上下文中,每一步都必须是DBIO类型的操作,直接遍历普通集合会让整个推导式变成普通的Scala集合遍历,而不是DBIO的流程组合,最终导致内层的插入操作根本不会被添加到事务里。
正确的实现方式
我们需要用flatMap(或for推导式的等价写法)+ DBIO.sequence来把所有操作扁平化成一个完整的DBIO流程,确保每一步插入都被纳入事务执行。
方式1:使用flatMap组合操作
// 构建完整的DBIO流程 val action = bookDao.insert(book).flatMap { bookId => // 遍历每个bookMod,生成对应的插入+关联插入操作 DBIO.sequence(bookMods.map { bookMod => bookModDao.insert(new bookModule(None, bookId, bookMod.moduleId, bookMod.isActive)).flatMap { bookModId => // 遍历每个userModRole,生成关联表插入操作,并用sequence组合成单个DBIO DBIO.sequence(userModRoles.map { userModRole => bookAssocDao.insert(new bookAssociation(None, bookModId, userModRole.moduleId, userModRole.roleId)) }) } }) } // 执行事务 db.run(action.transactionally)
方式2:使用正确的for推导式
val action = for { // 第一步:插入book,获取自增ID bookId <- bookDao.insert(book) // 第二步:遍历所有bookMod,为每个生成插入+关联插入的DBIO,并用sequence合并 _ <- DBIO.sequence(bookMods.map { bookMod => for { // 插入当前bookMod,获取自增ID bookModId <- bookModDao.insert(new bookModule(None, bookId, bookMod.moduleId, bookMod.isActive)) // 第三步:遍历所有userModRole,生成关联表插入操作,并用sequence合并 _ <- DBIO.sequence(userModRoles.map { userModRole => bookAssocDao.insert(new bookAssociation(None, bookModId, userModRole.moduleId, userModRole.roleId)) }) } yield () }) } yield () // 执行事务 db.run(action.transactionally)
关键知识点解释
flatMapvsmap:map只是转换DBIO的结果,不会执行内层的DBIO;而flatMap会把内层的DBIO合并到外层流程中,确保所有操作都被依次执行。DBIO.sequence:把Seq[DBIO[T]]转换成DBIO[Seq[T]],这样集合里的所有DBIO操作都会被纳入同一个执行流程,作为事务的一部分。- 事务的完整性:整个
action是一个完整的DBIO流程,用transactionally包裹后,所有插入操作要么全部成功,要么全部回滚,保证数据一致性。
内容的提问来源于stack exchange,提问作者priyanka goel
相关产品推荐
相关产品推荐

