Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 可重复读取隔离级别选择vs更新…其中_Mysql_Transactions_Innodb_Isolation Level - Fatal编程技术网

Mysql 可重复读取隔离级别选择vs更新…其中

Mysql 可重复读取隔离级别选择vs更新…其中,mysql,transactions,innodb,isolation-level,Mysql,Transactions,Innodb,Isolation Level,也许你可以在这里为我解释一些事情: DB=MySQL 5.7 存储引擎:InnoDB 隔离级别:可重复读取 下表: --------------- | MyTable | --------------- | PK | Concur | --------------- | 3 | 2 | --------------- 我在这个时间点没有进行任何交易,我选择如下记录 从PK=3的MyTable中选择* 并将结果存储在我的程序中 我现在开始一个DB事务。 在我的事务开始后,外部

也许你可以在这里为我解释一些事情:

DB=MySQL 5.7

存储引擎:InnoDB

隔离级别:可重复读取

下表:

---------------
|   MyTable   |
---------------
| PK | Concur |
---------------
| 3  |   2    |
---------------
我在这个时间点没有进行任何交易,我选择如下记录

从PK=3的MyTable中选择*

并将结果存储在我的程序中

我现在开始一个DB事务。 在我的事务开始后,外部进程将PK=3的记录的Concur从2增加到3

我还没有在我的事务中再次阅读该表

我在我的交易中发出以下查询:

更新MyTable集合Concur=3,其中PK=3,Concur=2

此操作将成功,影响0条记录。很明显,它是根据我的事务开始后更改的数据进行评估的。 仍在交易中,我随后询问:

从PK=3的MyTable中选择*

它将返回带有PK=3和Concur=2的记录,这是事务之前的值

为什么选择并更新。。。哪里表现不同,我错过了什么

我本以为更新。。。WHERE语句要么直接失败,而不是在0条记录受影响的情况下成功,要么在1条记录受影响的情况下成功,然后在提交时失败,但不是此混合匹配


有什么见解吗?

要受可重复读取隔离级别的影响,您必须在同一事务中。这意味着您的两个选择必须在一个事务中,因此它们不会受到您从外部事务在数据库中更改的位置的影响

所以,正如您所说,我在这个时间点上没有事务,我从MyTable中选择了select*这样的记录,其中PK=3,并将结果存储在我的程序中。您仅使用一条语句进行交易。 之后,您将启动一个更新事务

你应该做的是

 START TRANSACTION
      SELECT * FROM MyTable WHERE PK = 3
      ------                                        START TRANSACTION
      -----                                             UPDATE MyTable SET Concur = 3 WHERE PK = 3 AND Concur = 2                                            
      -------                                       END TRANSACTTION
      -------
      -------
      SELECT * FROM MyTable WHERE PK = 3
 END TRANSACTION

在左侧,您有选择事务,在右侧有更新。左侧事务不受更新的影响。

若要受可重复读取隔离级别的影响,您必须位于同一事务内。这意味着您的两个选择必须在一个事务中,因此它们不会受到您从外部事务在数据库中更改的位置的影响

所以,正如您所说,我在这个时间点上没有事务,我从MyTable中选择了select*这样的记录,其中PK=3,并将结果存储在我的程序中。您仅使用一条语句进行交易。 之后,您将启动一个更新事务

你应该做的是

 START TRANSACTION
      SELECT * FROM MyTable WHERE PK = 3
      ------                                        START TRANSACTION
      -----                                             UPDATE MyTable SET Concur = 3 WHERE PK = 3 AND Concur = 2                                            
      -------                                       END TRANSACTTION
      -------
      -------
      SELECT * FROM MyTable WHERE PK = 3
 END TRANSACTION
在左侧,您有选择事务,在右侧有更新。左侧事务不受此更新的影响

一致读取意味着InnoDB使用多版本控制在某个时间点向查询提供数据库的快照。查询会看到在该时间点之前提交的事务所做的更改,而不会看到稍后或未提交的事务所做的更改。此规则的例外情况是,查询可以看到同一事务中早期语句所做的更改。此异常会导致以下异常:如果更新表中的某些行,SELECT会看到更新行的最新版本,但也可能会看到任何行的较旧版本。如果其他会话同时更新同一个表,则异常意味着您可能会看到该表处于数据库中从未存在过的状态

重要的条件是,如果您更改了行,您的一致性读取将刷新,以便它包括您刚才所做的更改

但是,如果您进行更新,它将始终更新到行的最新版本,而不是事务的一致读取所能查看的版本。因此,如果另一个事务已经进行了更改,则您的更新可能不会产生净影响。这就是你观察到的情况

因此,您的事务发出了更新,但没有更改行

这可能不是您希望InnoDB的行为方式,但它确实是这样的

一致读取意味着InnoDB使用多版本控制在某个时间点向查询提供数据库的快照。查询会看到在该时间点之前提交的事务所做的更改,而不会看到稍后或未提交的事务所做的更改。此规则的例外情况是,查询可以看到同一事务中早期语句所做的更改。此异常会导致以下异常:如果更新表中的某些行,SELECT会看到更新行的最新版本,但也可能会看到任何行的较旧版本。如果其他会话同时更新同一个表,则异常意味着您可能会看到该表处于数据库中从未存在过的状态

重要人物 条件是,如果您更改行,您的一致性读取将刷新,因此它包含您刚才所做的更改

但是,如果您进行更新,它将始终更新到行的最新版本,而不是事务的一致读取所能查看的版本。因此,如果另一个事务已经进行了更改,则您的更新可能不会产生净影响。这就是你观察到的情况

因此,您的事务发出了更新,但没有更改行

这可能不是您希望InnoDB的行为方式,但它确实是这样的行为方式。

用以下信息传达您的更新意图:

另一方面

BEGIN;
...
(At this point another thread modifies the row...)
...
SELECT ... FOR UPDATE;  -- you are blocked until they COMMIT or ROLLBACK
用以下信息表明您的更新意图:

另一方面

BEGIN;
...
(At this point another thread modifies the row...)
...
SELECT ... FOR UPDATE;  -- you are blocked until they COMMIT or ROLLBACK

我理解这一点,但在我的问题中,我问的是更新中的区别。WHERE vs SELECT。UPDATE..WHERE的行为与本例中的READ COMMITTED类似。或者,如果从UPDATE…WHERE读取的数据实际上创建了快照,因为它是事务启动后对该表的第一次读取,那么后续的SELECT也应该返回新值。本质上,我是在问更新…何处和选择之间的隔离级别是否存在差异,或者它们是否相同,以及创建快照时在这两者之间的不一致性。我希望这是有道理的。我理解这一点,但在我的问题中,我想问的是更新中的区别。WHERE vs SELECT。UPDATE..WHERE的行为与本例中的READ COMMITTED类似。或者,如果从UPDATE…WHERE读取的数据实际上创建了快照,因为它是事务启动后对该表的第一次读取,那么后续的SELECT也应该返回新值。本质上,我是在问更新…何处和选择之间的隔离级别是否存在差异,或者它们是否相同,以及创建快照时在这两者之间的不一致性。我希望这是有意义的。自动提交的价值是什么?我在纵向控制事务自动提交的价值是什么?我在纵向控制事务感谢这是我在寻找的-更新…其中的行为设计相当于读取选择的提交行为。那太不幸了。我实际上不想锁定行,也无法切换隔离级别-因此,要从SELECT临时获得读取提交行为,我想我必须在当前事务之外使用单独的连接,除非您能想出其他方法?在启动事务之前将READ COMMITTED设置为隔离级别?无论如何,任何锁定选择也会得到相同的行为。任何锁定语句的行为都类似于READ COMMITED,因此您可以使用SELECT。。。锁定在共享模式下此更改为选择。。。对于MySQL 8.0.0中的共享,读取提交将是理想的,但我目前不能这样做,因为其他原因我没有影响力。我希望UPDATE和SELECT在这种情况下不会表现得像它们有不同的隔离级别一样。我故意不在一开始就锁定,因为在我得到更新之前可能需要几分钟。我们将该行用作信令和并发机制。似乎是作业的错误工具不幸的是,使用事务范围的数据是该任务的错误工具。您需要某种不受事务隔离约束的全局信号量。例如,我见过在Redis实例中使用密钥的系统,因此您的所有应用程序实例和线程都可以全局访问它。谢谢,这正是我要寻找的-更新…其中的行为按设计相当于读取选择的提交行为。那太不幸了。我实际上不想锁定行,也无法切换隔离级别-因此,要从SELECT临时获得读取提交行为,我想我必须在当前事务之外使用单独的连接,除非您能想出其他方法?在启动事务之前将READ COMMITTED设置为隔离级别?无论如何,任何锁定选择也会得到相同的行为。任何锁定语句的行为都类似于READ COMMITED,因此您可以使用SELECT。。。锁定在共享模式下此更改为选择。。。对于MySQL 8.0.0中的共享,读取提交将是理想的,但我目前不能这样做,因为其他原因我没有影响力。我希望UPDATE和SELECT在这种情况下不会表现得像它们有不同的隔离级别一样。我故意不在一开始就锁定,因为在我得到更新之前可能需要几分钟。我们将该行用作信令和并发机制。似乎是作业的错误工具不幸的是,使用事务范围的数据是该任务的错误工具。您需要某种不受事务隔离约束的全局信号量。例如,我见过在Redis实例中使用密钥的系统,因此您的所有应用程序实例和线程都可以全局访问它
在事务中,我们实际上需要几分钟才能到达更新…WHERE部分,我不想阻止任何那么长的内容。@FrankJ在这种情况下,您需要在事务中更改一列,执行该操作,然后在另一个事务中返回以撤消标记。所有相关的过程都必须尊重这面旗帜。是的,这是我下一个合乎逻辑的想法,不幸的是我们当时进入了比赛状态。@FrankJ-Ant,这就是为什么我说必须尊重这面旗帜。也就是说,它成为应用程序的问题。在数据库中,长时间运行的“事务”不是一个好主意。它是一个自动化过程,可能需要几分钟,对于非常大的客户机,可能需要半小时,并且必须完全失败/回滚。所以我确实需要这笔交易。我可以使用辅助DB连接来避开这一点,以减少竞争条件的时间。不幸的是,这是一个相当复杂的场景,有很多东西是固定的,我对此没有任何影响。谢谢你的帮助。我必须回到绘图板上。我研究过了,但实际上我不想在此时锁定行,因为事务中的过程实际上可能需要几分钟才能到达更新…WHERE部分,我不想阻止那么长的时间。@FrankJ在这种情况下,您需要在一个事务中更改一个列,执行该操作,然后在另一个事务中返回以撤消该标志。所有相关的过程都必须尊重这面旗帜。是的,这是我下一个合乎逻辑的想法,不幸的是我们当时进入了比赛状态。@FrankJ-Ant,这就是为什么我说必须尊重这面旗帜。也就是说,它成为应用程序的问题。在数据库中,长时间运行的“事务”不是一个好主意。它是一个自动化过程,可能需要几分钟,对于非常大的客户机,可能需要半小时,并且必须完全失败/回滚。所以我确实需要这笔交易。我可以使用辅助DB连接来避开这一点,以减少竞争条件的时间。不幸的是,这是一个相当复杂的场景,有很多东西是固定的,我对此没有任何影响。谢谢你的帮助。我得回到绘图板上去了。