何时使用 SELECT ... FOR UPDATE?

2023-11-23

请帮助我理解背后的用例SELECT ... FOR UPDATE.

问题1:以下是一个很好的例子SELECT ... FOR UPDATE应该使用?

Given:

  • 房间[id]
  • 标签[id, 名称]
  • room_tags[room_id, tag_id]
    • room_id 和 tag_id 是外键

该应用程序想要列出所有房间及其标签,但需要区分没有标签的房间和已删除的房间。如果不使用 SELECT ... FOR UPDATE,可能发生的情况是:

  • Initially:
    • 房间包含[id = 1]
    • 标签包含[id = 1, name = 'cats']
    • room_tags 包含[room_id = 1, tag_id = 1]
  • Thread 1: SELECT id FROM rooms;
    • returns [id = 1]
  • 话题2:DELETE FROM room_tags WHERE room_id = 1;
  • 话题2:DELETE FROM rooms WHERE id = 1;
  • 线程2:[提交交易]
  • Thread 1: SELECT tags.name FROM room_tags, tags WHERE room_tags.room_id = 1 AND tags.id = room_tags.tag_id;
    • 返回一个空列表

现在线程 1 认为房间 1 没有标签,但实际上该房间已被删除。为了解决这个问题,线程1应该SELECT id FROM rooms FOR UPDATE,从而防止线程 2 删除rooms直到线程 1 完成。那是对的吗?

问题2: 什么时候应该使用SERIALIZABLE事务隔离与READ_COMMITTED with SELECT ... FOR UPDATE?

答案应该是可移植的(不是特定于数据库的)。如果不可能,请解释原因。


实现房间和标签之间一致性并确保房间在删除后永远不会返回的唯一可移植方法是将它们锁定SELECT FOR UPDATE.

然而,在某些系统中,锁定是并发控制的副作用,并且无需指定即可获得相同的结果FOR UPDATE明确地。


为了解决这个问题,线程1应该SELECT id FROM rooms FOR UPDATE,从而防止线程 2 删除rooms直到线程 1 完成。那是对的吗?

这取决于您的数据库系统使用的并发控制。

  • MyISAM in MySQL(以及其他几个旧系统)确实在查询期间锁定整个表。

  • In SQL Server, SELECT查询在它们检查过的记录/页面/表上放置共享锁,而DML查询放置更新锁(稍后升级为独占锁或降级为共享锁)。独占锁与共享锁不兼容,因此SELECT or DELETE查询将锁定,直到另一个会话提交。

  • 在使用的数据库中MVCC (like Oracle, PostgreSQL, MySQL with InnoDB), a DML查询创建记录的副本(以一种或另一种方式),并且通常读取器不会阻止写入器,反之亦然。对于这些数据库,SELECT FOR UPDATE会派上用场:它会锁定SELECT or the DELETE查询直到另一个会话提交,就像SQL Server does.

什么时候应该使用REPEATABLE_READ事务隔离与READ_COMMITTED with SELECT ... FOR UPDATE?

一般来说,REPEATABLE READ不禁止幻像行(在另一个事务中出现或消失的行,而不是被修改的行)

  • In Oracle和更早的PostgreSQL版本,REPEATABLE READ实际上是一个同义词SERIALIZABLE。基本上,这意味着事务在启动后看不到所做的更改。所以在这个设置中,最后一个Thread 1查询将返回房间,就好像它从未被删除一样(这可能是也可能不是您想要的)。如果您不想在删除房间后显示它们,则应该使用以下命令锁定行SELECT FOR UPDATE

  • In InnoDB, REPEATABLE READ and SERIALIZABLE是不同的东西:读者SERIALIZABLE模式在它们评估的记录上设置下一个键锁,有效防止并发DML在他们。所以你不需要SELECT FOR UPDATE在可序列化模式下,但确实需要它们REPEATABLE READ or READ COMMITED.

请注意,隔离模式的标准确实规定您不会在查询中看到某些怪癖,但没有定义如何(使用锁定或使用MVCC或其他)。

当我说“你不需要SELECT FOR UPDATE“我真的应该添加“因为某些数据库引擎实现的副作用”。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

何时使用 SELECT ... FOR UPDATE? 的相关文章

  • 提交ajax表单并停留在同一页面不起作用

    我想将用户的评论存储在我的数据库中 当用户提交时 我不想将他们重定向到新页面 我有以下代码 但它不起作用 我的 HTML 代码
  • MySQL 命令输出在命令行客户端中太宽[重复]

    这个问题在这里已经有答案了 我在用mysql终端模拟器中的命令行客户端lxterminal在Ubuntu中 当我运行以下命令时 mysql gt select from routines where routine name simplep
  • SQL Server 数据归档解决方案

    我正在寻找一种解决方案来存档数据库中存在的数据 我的数据库是 SQL Server 2008 大约有 250 个表 我搜索网络并找到以下链接 http www dbazine com sql sql articles charran13 h
  • 在两个以上的表上使用内联接删除查询

    我想使用两个以上表上的内联接从表中删除记录 假设我有表 A B C D 其中 A 的 pk 在所有其他提到的表中共享 然后如何编写删除查询以使用表 B 和 A 上的内联接从表 D 中删除记录 因为条件是从这两个表中获取的 我需要从 DB2
  • 在 JSP 中迭代列表对象

    我正在做一个项目来尝试自学 spring 和 struts 我目前卡在 JSP 页面上 我有一个 pojo 类 其中包含带有 getter setter 的变量 eid 和 ename 我还有一个 sql 中的表 其具有相同的值和六个填充行
  • 工厂模式数据库连接

    我正在尝试使用 MySQL 实现数据库连接上的工厂模式 SQL Server 面临奇怪的错误 你调用的对象是空的 在 SQL 命令对象上 internal class SqlServerDB IDatabase private SqlCon
  • mysql变量赋值:如何强制赋值顺序?

    由于mysql是一种声明性语言 我找不到强制赋值变量顺序的方法 采取这个查询 SET v1 0 SET v2 0 SELECT v1 v2 FROM MyTable table WHERE v1 v2 is not null AND v2
  • 找出会话的默认 SQL Server 架构

    我需要知道正在执行某些 DDL 的 SQL 脚本中当前的默认架构是什么 我不需要设置架构 但我确实需要将对它的引用 名称或 ID 放入变量中 该脚本可能以 Windows 登录身份运行 因此以下内容还不够 SELECT name defau
  • 如何在 SQL Server 会话中设置自动提交?

    如何在 SQL Server 会话中设置自动提交 您可以通过将implicit transactions设置为OFF来打开自动提交 SET IMPLICIT TRANSACTIONS OFF 当设置为ON时 返回隐式事务模式 在隐式事务模式
  • 如何从表中选择层次结构中的最低级别

    我有一个具有父 子关系的表 Table A Column Id int Column Parent Id int Column Description text 一组示例数据如下 999 NULL Corp 998 999 Div1 997
  • WHERE 子句或 ON 子句中的 INNER JOIN 条件?

    我今天输错了一个查询 但它仍然有效并给出了预期的结果 我的意思是运行这个查询 SELECT e id FROM employees e JOIN users u ON u email e email WHERE u id 139840 但我
  • 我应该为 MySQL 使用什么 python 3 库? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 据我所知 MySQLdb 仍然没有移植到 Python 3 pypy 上似乎有另一个名为 PyMySQL
  • 获取 SQL 表上未使用的唯一值

    我有一个表 其中有一列描述数字 ID 该 ID 对于所有行都是唯一的 但它不是主键 数字 ID 是有限的 假设答案可以是从 1 到 10 SELECT ID FROM TABLE ID 1 2 5 我必须 通过 UI 向用户呈现未使用的值
  • SQL Server:比较两个表中的列

    我最近完成了从某些应用程序的旧版本到当前版本的迁移 在迁移数据库时遇到了一些问题 我需要一个可以帮助我比较两个表中的列的查询 我的意思不是行中的数据 我需要比较列本身来弄清楚我错过了表结构的哪些变化 看一下红门 SQL 比较 http ww
  • 无效的 PDO 查询不会返回错误

    下面的第二条 SQL 语句在 phpMyAdmin 中返回错误 SET num 2000040 INSERT INTO artikel artikel nr lieferant nr bezeichnung 1 bezeichnung 1
  • 简单的t-sql而不是触发器

    任何人都可以帮助解决简单的 t sql 脚本与板载触发器的问题吗 我使用非常简单的触发器将数据从一个表复制到另一个表 这些表之间没有关系 当我尝试在触发器创建后 从同一脚本 直接第一次插入数据时 我得到了所需的结果 但所有接下来的尝试都会失
  • 左连接 SQL 求和

    我有两张桌子想要加入 比如说表 a 和表 b 表 b 有许多行指向表 a 表 b 包含价格 实际上是一个购物篮 所以我想要的是表a中的所有记录和表b中的价格之和 我努力了 select a sum b ach sell from booki
  • 从多个选择列表中插入数据到mysql数据库(html形式)

    我制作了一个表格 其中有商店的 ID
  • $_SESSION 中保存大量信息可以吗?

    我需要存储许多数组 SESSION以防止从 MySQL 检索信息 可以吗 其中 太多 的信息有多少 SESSION还是没有 太多 谢谢 附 或者更好地使用http php net manual en book memcache php ht
  • 无法在 Centos 上安装 php-mysqli 扩展

    我正在尝试将 mysqli 扩展安装到 php yum install php mysqli 我收到下一个错误 Transaction Check Error file usr share mysql charsets Index xml

随机推荐