我正在为 SQL 数据库构建一组简单的查询。我遇到了一种我想防止的情况,但我不知道数据库理论术语来解释我所问的问题。
在此示例中,数据库上同时发生两个事务。事务 #1 开始,事务 #2 在 T1 之后开始,但 T2 在 T1 提交之前结束。
表 USERS 包含列 id、name、passwordHash
--Transaction #1
BEGIN TRANSACTION;
SELECT id from USERS where name = someName;
--do some work, transaction #2 starts and completes quickly while this work is being performed
UPDATE USERS SET name = newName where id = $id;
COMMIT;
--Transaction #2
BEGIN TRANSACTION;
SELECT id from USERS where name = someName;
UPDATE USERS SET passwordHash = newPasswordHash where id = $id;
COMMIT;
我希望执行某种安全检查,如果我正在更新一行,我只更新事务开始时存在的该行的相同版本。
在这种情况下,我希望事务 1 COMMIT
失败,因为事务 2 已经更新了属于名为 someName
的用户的行。
最佳答案
您可以使用 SELECT FOR UPDATE 和 NOWAIT 来锁定行,防止其他事务并发修改。这将保证您以后的更新将针对这些行的相同版本运行;在您的事务提交之前,其他事务无法更改这些行。
示例(使用 Postgresql):
交易1:
begin transaction;
select * from users where username = 'Fabian' for update nowait;
update users set passwordHash = '123' where username = 'Fabian';
commit;
事务 2,在事务 1 选择更新但未提交之后的某个位置:
> select * from users where username = 'Fabian' for update nowait;
ERROR: could not obtain lock on row in relation "users"
编辑
这通常称为悲观锁定。首先选择该行的事务将“获胜”,任何稍后选择更新的事务都将失败。如果您希望首先写入更改的事务获胜,您可能需要采用乐观锁定方法,如 @Laurence 所提议的。
关于sql - 防止并行事务更新行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20033816/