Lit*_*use 6 sql multithreading synchronization
在这些条件下,sql会出现竞争条件吗?
如果我在一个线程中运行此SQL更新,则调用它语句1:
更新项目设置标志= B,其中标志= A;
而这个在另一个运行的SQL更新调用它语句2:
更新项目设置标志= C其中标志= A;
每个线程是否可以读取Flag等于A的相同记录并用自己的值写入记录?这样声明1可以先写它然后声明2写它或反之亦然?
此问题的答案取决于数据库何时独占锁定更新.它是在找到记录之前还是在找到记录并评估where子句之后发生的?
首先,有三个锁定上下文:
然后你有四种锁定模式:
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锁定并最终执行但不匹配任何行.
排他锁,用于数据修改操作,例如 INSERT、UPDATE 或 DELETE 将在这种情况下使用。
独占锁确保不能同时对同一资源进行多次更新。
在这种情况下,您不会遇到竞争条件。
如果您有涉及多个表的更复杂的场景,那么您可能会遇到竞争条件或死锁。有很多方法可以避免这种情况,例如简化和分离查询等。
您还可以对查询应用提示,告诉 SQL 要使用哪种类型的锁。
http://msdn.microsoft.com/en-us/library/aa213026(v=sql.80).aspx