sql - 防止并行事务更新行

标签 sql database database-design transactions

我正在为 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/

相关文章:

java - 如何克服这个错误 "com.mongodb.diagnostics.logging.JULLogger log"

mysql - Oracle MySQL : Cannot add foreign key constraint

java - 选择具有 between where 限定符的命名参数查询

c# - 如果 SQL Server 2012 插入太大,我该如何截断插入?

php - PHP 和 MySQL 的 MCQ 考试系统

database-design - 为什么要在 SQL 文本列中存储分隔列表?

MySQL 转换为十进制不能按预期工作

mysql - 如何从分区中选择,同时在 MySQL 中连接它的名称

mysql ...in where 子句不明确

mysql - 在sql中重命名每个组的重复项