在事务和嵌套数据库写入(使用Scala)

Uri*_*Uri 7 playframework anorm playframework-2.0 playframework-2.1

假设我有以下方法:
在WebsitesList模型上:

def create(urls: List[String]) = DB.withTransaction(implicit c => {
    val websites = urls.map(Website.create(_))
    val listId: Option[Long] = SQL("INSERT INTO LIST (created_date, active) VALUES ({created_date}, {active})").
      on('created_date -> new Date(), 'active -> true).
      executeInsert()
    websites.foreach(websiteId =>
      SQL("INSERT INTO websites_list (list_id, website_id) VALUES ({listId}, {websiteId})").
      on('listId -> listId.get, 'websiteId -> websiteId.id).executeInsert()
    )

    throw new Exception()
  })
Run Code Online (Sandbox Code Playgroud)

并在网站模型:

def create(url: String): Website = DB.withConnection {
    implicit c =>
      val currentDate = new Date()
      val insertedId: Option[Long] = SQL("insert into websites (url, Date_Added) values ({url}, {date})").
        on('url -> url, 'date -> currentDate).
        executeInsert()
      Website(insertedId.get, url, currentDate)
  }
Run Code Online (Sandbox Code Playgroud)

如您所见,我在WebsitesList创建方法上启动一个事务,并且该方法调用网站模型的create方法.
我的目标是,如果由于某种原因无法创建WebsitesList,则删除创建的网站记录.为了测试它,我引发异常并且如预期的那样,不会创建WebsitesList和List记录.但是,网站记录在异常后不会回滚并保留在数据库中.

我的理论是,Website.create方法创建了一个新连接而不是使用现有连接.谁知道我怎么解决这个问题?

谢谢.

mab*_*aba 11

您可以更改签名以进行隐式连接,然后在create方法之外控制事务.

Website.scala

object Website {

  def create(url: String): Website = {
    DB.withConnection { implicit connection =>
      createWithConnection(url)
    }
  }

  def createWithConnection(url: String)(implicit connection: Connection): Website = {
    val currentDate = new Date()
    val insertedId: Option[Long] = SQL("insert into websites(url, Date_Added) values ({url}, {date})").
      on('url -> url, 'date -> currentDate).
      executeInsert()
    Website(insertedId.get, url, currentDate)
  }
}
Run Code Online (Sandbox Code Playgroud)

WebsiteList.scala

object WebsiteList {

  def create(urls: List[String]) = DB.withTransaction(implicit c => {
    createWithConnection(urls)
  })

  def createWithConnection(urls: List[String])(implicit connection: Connection) = {
    val websites = urls.map(Website.createWithConnection)
    val listId: Option[Long] = SQL("INSERT INTO LIST (created_date, active) VALUES ({created_date}, {active})").
      on('created_date -> new Date(), 'active -> true).
      executeInsert()
    websites.foreach(websiteId =>
      SQL("INSERT INTO websites_list (list_id, website_id) VALUES ({listId}, {websiteId})").
        on('listId -> listId.get, 'websiteId -> websiteId.id).executeInsert()
    )

    throw new Exception()
  }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的那样,WebsiteList我更改了DB.withConnectionto,DB.withTransaction因为您正在进行多次插入并希望它们在同一事务中一起提交.

这使您可以控制Connection应该共享的时间和位置.

例如,您可以在控制器中执行事务管理,该事务管理更好地了解应该使用事务的时间:

object SomeController extends Controller {
  def someAction(someData: String) = Action { implicit request =>
    DB.withTransaction { implicit connection =>
      SomeModel.create(someData)
      OtherModel.create(someData)
    }
  }
}

object SomeModel {
  def create(data: String)(implicit connection: Connection) {
  }
}

object OtherModel {
  def create(data: String)(implicit connection: Connection) {
  }
}
Run Code Online (Sandbox Code Playgroud)