Scala Play with Slick中的事务方法(类似于Spring @Transactional,也许吗?)

红棉

我知道scala作为一种功能语言,应该与Java等常见的OO语言不同,但是我确信必须有一种方法可以将一组数据库更改包装在单个事务中,从而确保原子性以及其他所有ACID属性。

slick docs(http://slick.lightbend.com/doc/3.1.0/dbio.html)中所述,DBIOAction允许将db操作分组到一个事务中,如下所示:

val a = (for {
  ns <- coffees.filter(_.name.startsWith("ESPRESSO")).map(_.name).result
  _ <- DBIO.seq(ns.map(n => coffees.filter(_.name === n).delete): _*)
} yield ()).transactionally

val f: Future[Unit] = db.run(a)

但是,在我的用例(以及我能想到的大多数现实示例)中,我有一个带有Controller的代码结构,该结构公开了我的REST端点的代码,该Controller调用了多个服务,每个服务都将数据库操作委托给DAO。

我通常的代码结构的一个粗略示例:

class UserController @Inject(userService: UserService) {
  def register(userData: UserData) = {
    userService.save(userData).map(result => Ok(result))
  }
}

class UserService @Inject(userDao: UserDao, addressDao: AddressDao) {
  def save(userData: UserData) = {
    for {
      savedUser <- userDao.save(userData.toUser)
      savedAddress <- addressDao.save(userData.addressData.toAddress)
    } yield savedUser.copy(address = savedAddress)
  }
}

class SlickUserDao {
  def save(user: User) = {
    db.run((UserSchema.users returning UserSchema.users)).insertOrUpdate(user)
  }
}

这是一个简单的示例,但是大多数服务层中都有更复杂的业务逻辑。

我不要

  1. 我的DAO具有业务逻辑并决定要运行的数据库操作。
  2. 从我的DAO返回DBAction并公开持久性类。首先,这完全破坏了使用DAO的目的,并使进一步的重构变得更加困难。

但是我绝对希望在我的整个Controller周围进行事务处理,以确保如果任何代码失败,该方法执行过程中所做的所有更改都将被回滚。

如何在Scala Play应用程序中使用Slick实现完全的控制器事务处理?我似乎找不到有关如何执行此操作的任何文档。

另外,如何禁用自动提交功能?我敢肯定有办法,我只是想念一些东西。

编辑:

因此,多读一点它,我现在觉得我更好地理解了slick如何使用到数据库和会话的连接。这很有帮助:http : //tastefulcode.com/2015/03/19/modern-database-access-scala-slick/

我正在做的是在未来进行构图的情况,根据本文,无法对同一类型的多种操作使用相同的连接和会话。

问题是:我真的不能使用任何其他种类的构图。我有相当多的业务逻辑,需要在两次查询之间执行。

我想我可以更改代码以允许我使用动作组合,但是正如我之前提到的,这迫使我在考虑事务性等方面对业务逻辑进行编码。那不应该发生的。它污染了业务代码,使编写测试变得更加困难。

任何解决此问题的方法?那里有任何git项目可以解决我错过的问题吗?或者,更激烈的是,是否有任何其他支持此功能的持久性框架?从我阅读的内容来看,Anorm很好地支持了这一点,但是我可能会误解它,并且不想更改框架以发现它不是(就像Slick那样)。

罗曼

光滑的东西没有事务注释之类的东西。您的第二个“不想要”实际上是要走的路。DBIO[User]从您的DAO回来是完全合理的,而这完全不会破坏他们的目的。这就是光滑的工作方式。

class UserController @Inject(userService: UserService) {
  def register(userData: UserData) = {
    userService.save(userData).map(result => Ok(result))
  }
}

class UserService @Inject(userDao: UserDao, addressDao: AddressDao) {
  def save(userData: UserData): Future[User] = {
    val action = (for {
      savedUser <- userDao.save(userData.toUser)
      savedAddress <- addressDao.save(userData.addressData.toAddress)
      whatever <- DBIO.successful(nonDbStuff)
    } yield (savedUser, savedAddress)).transactionally

    db.run(action).map(result => result._1.copy(result._2))
  }
}

class SlickUserDao {
  def save(user: User): DBIO[User] = {
    (UserSchema.users returning UserSchema.users).insertOrUpdate(user)
  }
}
  • save您的服务类别中的签名仍然相同。
  • 控制器中没有与数据库相关的内容。
  • 您可以完全控制交易。
  • 与原始示例相比,我找不到上面的代码更难维护/重构的情况。

还有一个非常详尽的讨论可能对您来说很有趣。请参阅Slick 3.0 withTransaction块,以便与库进行交互

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Scala Play with Slick中的事务方法(类似于Spring @Transactional,也许吗?)

来自分类Dev

Play Framework 2.2(scala)play.api.cache不包括在标准配置中吗?

来自分类Dev

在Scala中类似于Groovy的“ Power assert”之类的东西吗?

来自分类Dev

在Scala中类似于Groovy的“ Power assert”之类的东西吗?

来自分类Dev

Scala部署中的Play框架

来自分类Dev

Scala Play Framework Slick Session的问题

来自分类Dev

在 Play for Scala 方法中捕获异常

来自分类Dev

从Spring框架迁移到Play框架(Scala)

来自分类Dev

在Play for Scala中成为有状态的人可以吗?

来自分类Dev

验证Play Scala表单中数字的存在

来自分类Dev

在Play for Scala中序列化树

来自分类Dev

Scala Play中的可互换菜单

来自分类Dev

表单中的Scala Play上传文件

来自分类Dev

Scala Play JSON读取中的常量值

来自分类Dev

Play框架路线中的Scala反引号

来自分类Dev

如果Play / Scala JSON解析中的语句?

来自分类Dev

在Play 2.4 Scala中禁用单项测试

来自分类Dev

在scala / play中解析“ stringified” JSON

来自分类Dev

让Swagger在Play2 Scala中工作

来自分类Dev

Scala Play Json中的数组的JsPath

来自分类Dev

在Play / Scala中遍历多个JSON数组

来自分类Dev

在Scala的Play Framework 2.4中实现CORS

来自分类Dev

在Play 2.4 Scala中禁用单项测试

来自分类Dev

Play 框架中的 Scala 依赖注入

来自分类Dev

在 Play for Scala 的收益中返回未来的响应

来自分类Dev

Scala Play 中的动态构建 ws 请求

来自分类Dev

Play for Scala 中的连接不可用

来自分类Dev

Scala.JS 中的会话(和 Play)

来自分类Dev

使用Play中的Scala模板!scala.js中的框架