何时使用 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? 的相关文章

  • 如何在 Laravel 查询中使用多个 OR,AND 条件

    我需要 Laravel 查询帮助 我的自定义查询 返回正确结果 Select FROM events WHERE status 0 AND type public or type private 如何写这个查询Laravel Event w
  • SQLite HAVING 比较错误

    我有一个测试 SQLite 表 用于存储带有值的报告数据 CREATE TABLE IF NOT EXISTS test fact daily revenue date TEXT revenue NUMERIC product TEXT I
  • Hibernate 对集合的查询过滤器

    我想执行以下查询 from Item i where i categoryItems catalogId catId 然而 这会产生以下异常 非法尝试取消引用集合 所以我用谷歌搜索 找到了这个 Hibernate 论坛帖子https for
  • 如何使用PostGIS将多边形数据转换为线段

    我在 PostgreSQL PostGIS 中有一个多边形数据表 现在我需要将此多边形数据转换为其相应的线段 谁能告诉我如何使用 PostGIS 查询进行转换 提前致谢 一般来说 将多边形转换为线可能并不简单 因为没有一对一的映射 http
  • 查找 PostgreSQL 中所有范围集合的所有交集

    我正在寻找一种有效的方法来查找时间戳范围集之间的所有交集 它需要与 PostgreSQL 9 2 配合使用 假设这些范围代表一个人可以见面的时间 每个人都可以有一个或多个空闲时间范围 我想找到all可以召开会议的时间段 即所有人都有空的时间
  • SQL Server,插入 Excel“链接服务器”时出现“无效列名”错误

    我有一个简单的 Excel 电子表格文档 运行 Office 2013 我使用 Microsoft Office 15 0 Access 数据库引擎 OLE DB 提供程序 将其用作数据库 我可以使用 MS SQL Server Manag
  • 更改迁移中的自动​​增量值(PostgreSQL 和 SQLite3)

    我有一个托管在 Heroku 上的项目 想要更改表的自动增量起始值 我在本地使用 SQLite3 Heroku 使用 PostgreSQL 这是我在迁移中所拥有的 class CreateMytable lt ActiveRecord Mi
  • 在 SQL Server 中处理日期

    我正在开发一个 ASP NET 网站 我从网页获取日期 然后根据用户输入我想从 SQL Server 数据库获取结果 使用存储过程 问题是我只能从用户界面获取这种格式的日期2016 10 08这是字符串类型 但在数据库中 我有一个类型为da
  • Mysql 检索所有有限制的行

    我想检索特定用户的所有行 限制为 0 x 所以我只是想问是否有任何方法可以检索 mysql 中的所有行 而不调用返回 x 的 count id 的方法 而不重载现有函数 该函数在查询中根本没有限制 与我们的 string Relace 功能
  • 如何在 Visual Studio 中更改 Azure 数据库表的列顺序

    我整个下午都在寻找在 MS Visual Studio 2022 中重新排序 Azure 数据库表列的方法 没有运气 在其他应用程序中 可以通过拖动或剪切和粘贴轻松重新排列列 这里无能为力 此时 我什至不确定可以在 VS 中移动列 我只对
  • 避免连接失败时出现空指针

    我有我的域类 带有命名查询 class Atendimento implements Serializable Funcionario funcionario static mapping funcionario column FUNCOD
  • Mysql 中 UNION 子句的替代方案

    我有两张桌子 表 a 表 b table a ID 1 2 3 4 5 7 table b ID 2 3 4 5 6 我必须得到这样的输出而无需UNION命令 ID 1 2 3 4 5 6 7 注意 我有一个联合解决方案 select fr
  • 在sqlite SQL语句中与order by子句结合使用limit

    下面的两条 SQL 语句总是会产生相同的结果集吗 1 SELECT FROM MyTable where Status 0 order by StartTime asc limit 10 2 SELECT FROM SELECT FROM
  • hibernate锁等待超时超时;

    我正在使用 Hibernate 尝试模拟对数据库中同一行的 2 个并发更新 编辑 我将 em1 getTransaction commit 移至 em1 flush 之后我没有收到任何 StaleObjectException 两个事务已成
  • 如何在存储过程中实现 sql 搜索功能 (Sql Server 2008)

    我需要编写一个存储过程 该过程将使用 sql server 2008 根据可选参数搜索表 将会有两种模式 基本搜索模式 我们只传递一些文本 高级搜索模式 使用可选参数而不使用 SearchText 为了进行测试 我使用 AdventureW
  • 忽略重复条目并在 EF Core 中的 DbContext.SaveChanges() 上提交成功条目

    我有一个 ASP Net Core 2 2 Web API 在我的一个控制器操作中 我向 MySQL 数据库表添加了一堆行 我使用的是 Pomelo 例如 dbContext AddRange entities dbContext Save
  • 有没有办法以编程方式轻松更改多个 SSIS 包上的服务器名称?

    作为发布周期的一部分 我们正在创建多个 SSIS 包来迁移大型数据库 我们最终可能会得到大约 5 10 个 SSIS 包 由于我们有 4 个环境 开发 QA 登台 生产等 是否有一种有效的方法可以在每个 SSIS 包经历不同的服务器环境时更
  • 使用 where 进行 select 语句时,HSQLDB 用户缺乏权限或未找到对象错误

    我的数据库使用 SQuirrel SQL 客户端版本 3 5 3 和 HSQLDB 我已经能够为其指定相应的驱动程序 内存中 并创建一个别名 我创建了一个表 CREATE TABLE ENTRY NAME VARCHAR 100 NOT N
  • 在 SQL 数据库中存储“列表”的最正确方法是什么?

    因此 我读了很多关于如何将多个值存储到一个列中是一个坏主意 并且违反了数据标准化的第一条规则 令人惊讶的是 这不是 不要谈论数据标准化 所以我需要一些帮助 目前我正在为我工 作的地方设计一个 ASP NET 网页 我想根据此人所属的 Act
  • MySQL 查询计算上个月

    我想计算上个月的订单总额 我收到了从当前日期获取当月数据的查询 SELECT SUM goods total AS Total Amount FROM orders WHERE order placed date gt date sub c

随机推荐