与 Doobie 的单笔交易中的多个查询?

Multiple queries in a single transaction with Doobie?

假设我有两个案例 类 C1C2,每个案例都继承自特征 T。我有两个 Query0 对象,这些对象由 类 Query0[C1]Query0[C2] 参数化。目标是当我执行这些查询时,我想获得一个 List[T] 包含这两个查询的结果。现在我可以很好地处理单独的事务。

def executeQuery[A <: T](query: Query0[A]): List[A]=
    transactor.use { xa => query.stream.compile.toList.transact(xa) }.unsafeRunSync

val query1: Query0[C1] = generateQuery1
val query2: Query0[C2] = generateQuery2

val results: List[T] = executeQuery(query1) ++ executeQuery(query2)

问题是我使用 BigQuery 作为数据库后端,事务有很多与之相关的开销。我希望在一个事务中执行这两个查询并让它 return 一个 List[T] 对象。有办法吗?

如果您不关心这两个查询的顺序,我建议您 compile 每个查询独立进入 ConnectionIO[List[A]],使用 mapN 组合它们(因为 ConnectionIO[T]Apply 个实例)和 transact 在一次交易中组合 ConnectionIO[List[A]

import cats.effect.{Async, ContextShift, Resource}
import cats.syntax.apply._
import doobie.Query0
import doobie.implicits._
import doobie.util.transactor.Transactor

class SomeDAO[F[_]: Async: ContextShift, T] {

  val transactor: Resource[F, Transactor[F]] = ???

  def compile[A <: T](query: Query0[A]): doobie.ConnectionIO[List[A]] =
    query.stream.compile.toList

  def executeTwo[A <: T](query1: Query0[A], query2: Query0[A]): F[List[A]] =
    transactor.use { xa =>
      (compile(query1), compile(query2))
        .mapN(_ ++ _)
        .transact(xa)
    }
}

我也得到了一个解决方案,只需将流附加到彼此即可

transactor.use { xa =>
    val stream = generateQuery1.stream ++ generateQuery2.stream
    stream.compile.toList.transact(xa)
}.unsafeRunSync