通过不同的模型使数据库调用成为原子

Make DB calls through different models atomic

假设有两个模型,Model1Model2,每个模型都有一组调用DB来检索或写入数据的基本方法。对于一个 Model1,可以存在多个 Model2,当插入一个 (Model1, List[Model2]) 时,所有这些数据都来自同一个表单。当前的实现执行以下操作:

  1. 使用 Model1 的插入方法插入 Model1 实例。
  2. 正确插入 Model1 后,使用 Model2 的插入方法继续插入 List[Model2]

问题是,如果在插入 Model2 之一时出现问题,Model1 将保留在数据库中。一个解决方案是捕获 anorm 抛出的任何异常,并通过执行与它完全相反的操作来撤消之前执行的任何内容。但是是否已经有可以使用的解决方案?捕获所有已执行的数据库调用并在需要时还原它们的东西?

您要找的是DB.withTransaction。和DB.withConnection完全一样,只是把autocommit设置为false,这样如果抛出任何异常,整个事务都会回滚。

示例:

case class Model1(id: Long, something: String, children: List[Model2])

case class Model2(id: Long, name: String)

object Model1 {

    def create(model: Model1): Option[Model1] = {
        DB.withTransaction { implicit c =>
            SQL(...).executeInsert().map { id =>
                 model.copy(
                     id = id,
                     children = Model2.create(model.children)
                 )
            }
        }
    }

}

object Model2 {

    def create(models: List[Model2])(implicit c: java.sql.Connection): List[Model2] = {
       ...
    }

}

注意 Model2.create 如何接受隐含的 Connection 参数。这样它将使用与 Model1.create 事务相同的 Connection,并允许在失败时回滚。我省略了精细的实现细节,因为关键只是使用 withTransaction,并且 运行 每个查询都使用相同的 Connection.