我们假设有两个模型Model1
和Model2
,每个模型都有一组调用DB来检索或写入数据的基本方法。对于一个Model1
,可以存在多个Model2
,当插入(Model1, List[Model2])
时,所有这些数据都来自同一表单。当前的实现执行以下操作:
Model1
的插入方法插入Model1
实例。Model1
后,请继续使用List[Model2]
的插入方法插入Model2
。问题是如果在插入Model2
之一时出现问题,Model1
将保留在数据库中。一个解决方案是捕获anorm
抛出的任何异常,并通过执行与之完全相反的操作来撤消之前执行的任何异常。但是有没有可以使用的解决方案?捕获所有已执行的DB调用并在需要时还原它们的东西?
答案 0 :(得分:1)
您正在寻找的是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
参数。这样它将使用与Connection
事务相同的Model1.create
,并允许在失败时回滚。我遗漏了很好的实施细节,因为关键是使用withTransaction
,并在同一Connection
上运行每个查询。