【发布时间】:2012-06-11 17:54:03
【问题描述】:
请帮助我了解 SELECT ... FOR UPDATE 背后的用例。
问题 1:下面是什么时候应该使用 SELECT ... FOR UPDATE 的一个很好的例子吗?
给定:
- 房间[id]
- 标签[id, name]
- room_tags[room_id, tag_id]
- room_id 和 tag_id 是外键
应用程序想要列出所有房间及其标签,但需要区分没有标签的房间和已删除的房间。如果不使用 SELECT ... FOR UPDATE,可能发生的情况是:
- 最初:
- 房间包含
[id = 1] - 标签包含
[id = 1, name = 'cats'] - room_tags 包含
[room_id = 1, tag_id = 1]
- 房间包含
- 线程 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:[提交事务]
- 线程 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 和 SELECT ... FOR UPDATE?
答案应该是可移植的(不是特定于数据库的)。如果这不可能,请解释原因。
【问题讨论】:
-
您使用的是哪个 RDBMS?
-
@Quassnoi,如问题底部所述,我正在寻找一种可移植(非特定于数据库)的解决方案。
-
REPEATABLE_READ和READ_COMMITTED选项是可移植选项吗?我得到的唯一结果是 MSSQL 服务器 -
@BillyONeal:请注意,隔离模式保证您不会看到他们不允许的怪癖,但不要说他们允许的怪癖。这意味着设置,比如说,
READ COMMITTED模式并没有定义你是否会真正看到另一个事务提交的记录:它只是确保你永远不会看到未提交的记录。 -
select ... for updateonrooms仍将允许删除room_tags,因为它们是单独的表。您的意思是问for update子句是否会阻止删除rooms?
标签: mysql sql sql-server transactions select-for-update