首页 > 解决方案 > 使用 Doobie 在单个事务中进行多个查询?

问题描述

假设我有两个案例类C1C2每个类都继承自 trait 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 作为数据库后端,并且事务有很多与之相关的开销。我希望在一个事务中执行这两个查询并让它返回一个 List[T] 对象。有没有办法做到这一点?

标签: scalascala-catsdoobie

解决方案


如果您不关心这两个查询的顺序,我建议您将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)
    }
}

推荐阅读