为什么mysql没有‘;当两个事务同时更新时,是否在可重复读取模式下锁定行?

为什么mysql没有‘;当两个事务同时更新时,是否在可重复读取模式下锁定行?,mysql,postgresql,scala,transactions,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==========

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

  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(它们都处于可重复模式)。我认为“一”事务将失败,因为并发更新

事实上,postgresql是这样的,但是mysql毫无例外地运行,“一”事务覆盖了“两”事务的结果。这意味着结果丢失,这非常烦人

    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  
有人能帮我吗

问题解决了。我已经将一些代码发布到github,使用
进行更新

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

ALTER TABLE table_name ENGINE = InnoDB;
注:

如果需要锁定所选记录,则必须使用
SELECT。。。用于更新
(;)。但有一个解决办法:

参考资料:


  • 这个问题与Java无关。你确定你使用的是两个不同的(物理)连接,因此是两个不同的事务吗?我对postgres不太了解,但在mysql(innodb)中,默认情况下,
    普通选择(没有显式锁定,例如用于更新)不会锁定任何内容,它只是确保所有select语句在这里彼此一致。您可以执行比较,然后更新sql,如
    set name=“new”where name=“old”
    。看看这里,确保只有
    innodb
    支持事务。@jilen我已经检查过mysql中的表是否使用innodb(它是mysql 5.7中的默认引擎)是的,在我应用
    val query=Tables.User.filter(u.id==2.map)之后;Q.queryNA[String](query.selectStatement+“FOR UPDATE”)。执行
    。mysql中的结果变成了
    -f2-f1
    ,即
    f2
    现在没有丢失。但我认为这仍然很奇怪,postgresql的结果就是我想要的。不管怎样,谢谢。如果“postgresql的结果”是你想要的,确切的方法是实际使用Postgres。在处理并发性方面有很多细微的差别,MySQL在这方面(相对而言)是一个缺乏经验的新手。要在MySQL中获得类似但不精确的效果,您可以使用。但它有一个副作用:第一次更新将等到第二次失败。