为什么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中获得类似但不精确的效果,您可以使用。但它有一个副作用:第一次更新将等到第二次失败。