Doobie 和 DB 访问组合在 1 个事务内



Doobie 书中说,从存储库层返回 ConnectionIO 是一个很好的做法。它提供了链接调用并在一个事务中执行它们的能力。 很好,很清晰。

现在让我们假设我们正在开发 REST API 服务,我们的场景是:

  1. 在数据库中查找对象
  2. 对此对象执行一些异步操作(使用 cats.effect.IO 或 monix.eval.Task(。
  3. 将对象存储在数据库中。

我们希望在 1 个事务中执行所有这些步骤。问题是,如果没有transactor.trans()为我们提供的自然转变,我们就在 2 个 monads 中工作 -TaskConnectionIO.那是不可能的。

问题是 - 如何将 doobieConnectionIO与任何效果 monad 混合在 1 个组合物中,例如我们在 1 个事务中工作并能够在世界末日提交/回滚所有数据库突变?

谢谢!

上级: 小例子

def getObject: ConnectionIO[Request]                      = ???
def saveObject(obj: Request): ConnectionIO[Request]       = ???
def processObject(obj: Request): monix.eval.Task[Request] = ???
val transaction:??? = for {
obj       <- getObject             //ConnectionIO[Request]
processed <- processObject(obj)    //monix.eval.Task[Request]
updated   <- saveObject(processed) //ConnectionIO[Request]
} yield updated

UPD2:@oleg-pyzhcov 提供的正确答案是将您的效果数据类型提升到如下所示ConnectionIO

def getObject: ConnectionIO[Request]                      = ???
def saveObject(obj: Request): ConnectionIO[Request]       = ???
def processObject(obj: Request): monix.eval.Task[Request] = ???
val transaction: ConnectionIO[Request] = for {
obj       <- getObject                                           //ConnectionIO[Request]
processed <- Async[ConnectionIO].liftIO(processObject(obj).toIO) //ConnectionIO[Request]
updated   <- saveObject(processed)                               //ConnectionIO[Request]
} yield updated
val result: Task[Request] = transaction.transact(xa)

doobie 中的ConnectionIO有一个cats.effect.Async实例,它允许您通过liftIO方法将任何cats.effect.IO转换为ConnectionIO

import doobie.free.connection._
import cats.effect.{IO, Async}
val catsIO: IO[String] = ???
val cio: ConnectionIO[String] = Async[ConnectionIO].liftIO(catsIO)

对于monix.eval.Task,您最好的选择是使用Task#toIO并执行相同的技巧,但您需要在范围内Schedulermonix。

相关内容

  • 没有找到相关文章

最新更新