什么时候sql独占锁定更新语句中的行?

Lit*_*use 6 sql multithreading synchronization

在这些条件下,sql会出现竞争条件吗?

如果我在一个线程中运行此SQL更新,则调用它语句1:

更新项目设置标志= B,其中标志= A;

而这个在另一个运行的SQL更新调用它语句2:

更新项目设置标志= C其中标志= A;

每个线程是否可以读取Flag等于A的相同记录并用自己的值写入记录?这样声明1可以先写它然后声明2写它或反之亦然?

此问题的答案取决于数据库何时独占锁定更新.它是在找到记录之前还是在找到记录并评估where子句之后发生的?

Jus*_*art 5

首先,有三个锁定上下文:

  • 数据库级别锁定
  • 表级锁定
  • 行级锁定

然后你有四种锁定模式:

  • IX
  • IS
  • X
  • 小号

IX和IS锁是"意图"锁.在获取其他类型的锁之前,会保留这些锁.X锁是独占(写)锁,S锁是共享(读)锁.

锁(IX,IS,X或X)锁可以在任何上下文级别进行.例如,数据库级别的X锁定将阻止数据库中的所有其他操作.这是SQLlite采用的锁类型.在读取期间对整个数据库进行S锁定,并在写入期间对整个数据库进行X锁定.写入将等待任何S锁完成,并将阻止新的S和X锁,直到释放写锁.这提供了可序列化的隔离事务级别.

对于MySQL,锁定取决于存储引擎.MyISAM将对整个(组)表进行X和S锁定.X锁将等待现有的S或X锁并阻止新锁.新的X锁将在队列中被赋予更高的优先级,在新的S锁之前移动.可以通过设置LOW_PRIORITY_UPDATES来更改此行为,这可能导致写入饥饿,因为写入将被取消优先级,有利于读取.

在MySQL中可以使用'FLUSH TABLES WITH READ LOCK'在整个数据库上获得X锁定.

InnoDB通过索引读取来锁定行.InnoDB锁定索引记录并在遍历索引记录时锁定记录.InnoDB使用称为"间隙"锁的特殊锁来确保REPEATABLE-READ事务隔离级别.锁保存在索引条目上,因此如果表没有为UPDATE查询编制索引,则会锁定许多行.请注意,InnoDB不会为正常的SELECT查询创建S锁.它使用行版本控制,而不是行级锁定来实现一致的快照.

获取X锁时,数据库需要检测死锁.考虑以下:

>connection 1
start transaction;
update T set c = c + 1 order by id asc;

>connection 2
start transaction;
update T set c = c - 1 order by id desc;
Run Code Online (Sandbox Code Playgroud)

在行锁定模型中,这两个语句不能同时成功完成.第一个将永远等待获得第二个持有的锁,反之亦然.数据库将选择一个要回滚的连接.InnoDB会选择连接数量最少的连接.MyISAM将锁定整个表,无论哪个连接首先获取锁,然后第二个将在第一个完成后运行.

您给出的简单示例将通过任何上下文(数据库,表或行)中的X锁解决.如果两个连接以完全相同的类型开始,则运行两个尝试更新同一行的更新,两者都将尝试获取X锁.只有一个连接可以获得X锁.无法准确确定哪一个将获得锁定.另一个连接必须等到锁被释放,直到它可以获得X锁.请记住,如果行被DELETE或UPDATE锁定,那么等待后服务员可能最终没有获取锁,因为数据库中没有任何东西可以锁定.

在您的示例中,第一个获取X锁定的UPDATE,然后第二个UPDATE将等待X锁定并最终执行但不匹配任何行.


Pet*_*eGO 0

排他锁,用于数据修改操作,例如 INSERT、UPDATE 或 DELETE 将在这种情况下使用。

独占锁确保不能同时对同一资源进行多次更新。

在这种情况下,您不会遇到竞争条件。

如果您有涉及多个表的更复杂的场景,那么您可能会遇到竞争条件或死锁。有很多方法可以避免这种情况,例如简化和分离查询等。

您还可以对查询应用提示,告诉 SQL 要使用哪种类型的锁。

http://msdn.microsoft.com/en-us/library/aa213026(v=sql.80).aspx