当两个事务同时更新时,为什么mysql不会在可重复读取模式下锁定行?

时间:2014-08-31 06:59:03

标签: mysql postgresql scala transactions

我不知道是否忘记设置一些属性以启用此功能 我有两个事务将更改同一个表中的同一行。

  val f1 = Future {
  mysqlDB.withTransaction {
    implicit session =>
      println("one===========query begin")
      val name = Tables.User.filter(_.id === 2).map(_.name).run
      println("one=========="+name)
      Thread.sleep(3000)
      println("one update change to x-f1")
      Tables.User.filter(_.id === 2).map(_.name).update(name + "-f1")
      println(Tables.User.filter(_.id === 2).run)
      println("one============query end")
  }
}

val f2 = Future {
  mysqlDB.withTransaction {
    implicit session =>
      println("two===========query begin")
      val name = Tables.User.filter(_.id === 2).map(_.name).run
      println("two==========="+name)
      Thread.sleep(2800)
      println("two update change to x-f2")
      Tables.User.filter(_.id === 2).map(_.name).update(name + "-f2")
      println(Tables.User.filter(_.id === 2).run)
      println("two============query end")
  }
}

Await.result(f1, 10.seconds)
Await.result(f2, 10.seconds)  

我使用上面相同的代码测试postgresql和mysql(它们都处于可重复模式)。我认为" one"事务将因为并发更新而失败。

事实上,postgresql确实如此,但mysql毫无例外地运行,并且" one"交易覆盖了"二"的结果。 transaction.It意味着结果丢失非常烦人。

    Run starting. Expected test count is: 2
    JDBCTestSpec2:
    transcation
    two===========query begin
    one===========query begin
    one============Vector(ccc)
    two==========Vector(ccc)
    two update change to x-f2
    Vector(UserRow(2,Vector(ccc)-f2))
    two============query end
    one update change to x-f1
    - should lock a row(postgresql) *** FAILED ***
      org.postgresql.util.PSQLException: 错误: 由于同步更新而无法串行访问
      at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2161)
      at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1890)
      at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
      at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:560)
      at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:417)
      at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:363)
      at scala.slick.driver.JdbcInvokerComponent$UpdateInvoker$$anonfun$update$1.apply(JdbcInvokerComponent.scala:88)
      at scala.slick.driver.JdbcInvokerComponent$UpdateInvoker$$anonfun$update$1.apply(JdbcInvokerComponent.scala:84)
      at scala.slick.jdbc.JdbcBackend$SessionDef$class.withPreparedStatement(JdbcBackend.scala:191)
      at scala.slick.jdbc.JdbcBackend$BaseSession.withPreparedStatement(JdbcBackend.scala:389)
      ...
    transcation
    two===========query begin
    one===========query begin
    two===========Vector(ccc)
    one==========Vector(ccc)
    two update change to x-f2
    Vector(UserRow(2,Vector(ccc)-f2))
    two============query end
    one update change to x-f1
    Vector(UserRow(2,Vector(ccc)-f1))
    one============query end  

有没有人可以帮助我?

问题解决了。我已经使用FOR UPDATE向github发布了一些代码:
https://gist.github.com/fairjm/99ce55160d4a4adf350b

1 个答案:

答案 0 :(得分:2)

正如所指出的,@ jilen表必须使用InnoDB存储引擎来支持MySQL中的事务。 要将表转换为InnoDB表运行语句:

ALTER TABLE table_name ENGINE = InnoDB;

注意:

如果您需要锁定所选记录,则必须使用SELECT ... FOR UPDATEmysql syntax; postgresql syntax)。它是is not supported natively in Slick,但有一种解决方法:https://gist.github.com/cvogt/d9049c63fc395654c4b4

参考文献:

  1. Transaction and Atomic Operation Differences
  2. ALTER TABLE Syntax
  3. Feature Request: Support for "SELECT ... FOR UPDATE"