7

假设我有以下方法:
在 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()
  })

在网站模型上:

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)
  }

如您所见,我在 WebsitesList 的 create 方法上启动了一个事务,该方法调用了 Website 模型的 create 方法。
如果由于某种原因无法创建网站列表,我的目标是删除创建的网站记录。为了对其进行测试,我提出了一个异常,并且正如预期的那样,没有创建 WebsitesList 和 List 记录。但是,网站记录在异常发生后不会回滚并保留在数据库中。

我的理论是 Website.create 方法创建了一个新的连接,而不是使用现有的。任何人都知道我该如何解决这个问题?

谢谢。

4

1 回答 1

11

您可以更改签名以采用隐式连接,然后在创建方法之外控制事务。

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)
  }
}

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()
  }
}

正如您在 I 中看到的那样,因为您正在执行多个插入并希望它们在同一个事务中一起提交,所以WebsiteList我将其更改为DB.withConnectionDB.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) {
  }
}
于 2013-09-12T07:19:10.823 回答