mysql - 隔离级别是否仅适用于 SELECTS 而不适用于 UPDATES?

标签 mysql database oracle postgresql

隔离级别是否仅适用于 SELECTS 而不适用于 UPDATES?

演示 SELECTS 不同隔离行为的场景

1) 0:00 Thread A runs a query that returns 1000 rows that takes 5 minutes to complete
2) 0:02 Thread B runs a query that returns the same 1000 rows
3) 0:05 Thread A updates the last 1 rows in this result set and commits them
4) 0:07 Thread B's query returns* 

根据隔离级别,#4 中的结果集要么包含线程 A 的更改,要么不包含。 更新也是如此吗?

以下是一个示例场景:

Thread A: UPDATE ... WHERE primary_key = 1234 AND version = 5
Thread B: UPDATE ... WHERE primary_key = 1234 AND version = 5

如果线程 A 和线程 B 同时进入它们的事务,并且线程 B 在线程 A 之后执行更新,线程 B 的更新会失败还是会“看到”版本 5 的记录并因此成功?

是否依赖于数据库?例如Oracle vs MySql vs PostgreSQL?

最佳答案

假设您打算展示许多 ORM 使用的“乐观锁定”模式,例如:

Thread A: UPDATE ... SET ..., version = 6 WHERE primary_key = 1234 AND version = 5
Thread B: UPDATE ... SET ..., version = 6 primary_key = 1234 AND version = 5

然后在所有合理的隔离级别(我不是 100% 确定 READ UNCOMMITTED - 大多数数据库甚至不支持它)线程 B 将不匹配任何行并且没有效果。

例如,在 PostgreSQL 中,线程 B 最初将匹配与 A 相同的行,但阻塞在行更新锁上,直到线程 A 提交或回滚。此时它将重新检查条件并发现如果线程 A 已提交则它不再匹配,因此它什么都不做。行锁定意味着序列化冲突永远不会在这种特殊情况下发挥作用。

在任何理智的数据库中,只有两个更新中的一个会成功——第二个更新要么匹配零行,要么因序列化失败而中止,这取决于隔离级别和数据库实现。至少在 5.5 中,即使在带有 InnoDB ( see detailed explanation and demo in this answer ) 的 MySQL 中也是如此。如果您使用的是 MyISAM,那么正确性和可靠性显然对您来说不是什么大问题;-)

我不知道有任何数据库对 UPDATESELECT 应用不同的隔离规则。毕竟,UPDATE 需要为其 WHERE 子句、子查询等提供与 SELECT 相同的隔离保证。 UPDATE 可以死锁,而 SELECT 不能(在 PostgreSQL 中;显然它们在 MySQL+InnoDB 中可以)。与 SELECT 不同,UPDATESERIALIZABLE 隔离模式下会出现序列化失败 - 但它们具有相同的可见性规则。

PostgreSQL 关于 concurrency control 的文档很好地解释了这一点。

关于mysql - 隔离级别是否仅适用于 SELECTS 而不适用于 UPDATES?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13431552/

相关文章:

mysql - Magento 中的自定义查询以将数据插入数据库

java - 获取前几个月的第一个和最后一个日期

java - 有没有办法用 hibernate POJO 映射表函数?

MySql 如何使用查询根据类型创建一行并添加子表?

mysql - 选择一个月内和24小时内MySQL的用户状态

php - 如何使用 php sprintf append 正值 "+"但忽略空值

php - MySQL Innodb 从非常大的数据库中删除/清除行

mysql - 使用 mysql 的 sql 语法,它将按循环顺序返回直到最后一条记录

java - 连接到 oracle 时出错。获取方法 t2cGetCharSet 的 UnsatisfiedLinkError

mysql - SQL Openquery - 对象没有列