什么是MySQL(或任何RDBMS)中的锁定以及何时使用它?使用示例的Layman解释会很棒!
答案 0 :(得分:14)
我们有一个联合银行账户,余额为200美元
我去自动取款机并将我的卡放入机器,机器检查我的余额是200美元
与此同时,你进入银行并要求50美元,出纳员开出你的账户并确认你有钱。
我要求提款200美元,机器计算我的钱给我200美元,我的余额设定为0美元
出纳员计算您的钱并给您50美元,系统然后将该帐户的余额更新为150美元(200美元 - 50美元撤回)。
所以现在我们还有250美元的现金和150美元的账户。 200美元的利润。
数据库应该使用锁来防止两个事务同时发生。
问题是,如果以这种方式处理每个事务,那么我们将失去并发性并且性能会受到影响,因此根据场景使用不同的transaction isolation levels
,例如您可能不关心某人可以修改已在事务中读取的数据。
http://en.wikipedia.org/wiki/Isolation_%28database_systems%29
您应该了解这些并了解它们适用的场景。
答案 1 :(得分:7)
锁定对于避免两个用户同时修改数据至关重要。您可能认为这不太可能,但根据应用程序的不同,如果不同用户经常更改相同的数据,则存在重大风险。
想象一下以下情况没有使用锁:John打开他的屏幕(他不知道他正在使用数据库,他只是一个正在看漂亮屏幕的最终用户),修改了一些数据,然后点击“保存”。假设John在9:30打开屏幕,然后在9:32保存数据。
然而,Mary在9:29打开了完全相同的屏幕和相同的记录。她当时看到约翰在9:30做的相同数据。然后,她更新了记录,并在9:31点击“保存”。
保存了哪些数据?约翰或玛丽?
玛丽高兴地继续处理其他记录,当她稍后回来打开记录时,她发现她的变化已经丢失了,她看到了约翰的变化!!
请注意,必须明智地使用锁定以防止意外的副作用。例如,假设您的程序在每次打开它时都会锁定记录进行更改。如果John锁定了记录,并且会话屏幕打开以便吃午饭或者他失去联系,会发生什么?锁可以长时间保持在那里,锁定和不可更改,同时禁止其他人改变(甚至查看)该记录。其他考虑因素可能是性能,因为数据库锁定和解锁记录的时间可能会因大量事务而变得明显。
了解锁定对于维护满意的用户和数据完整性至关重要。请查看文档。
答案 2 :(得分:3)
几天前,我回答了a question on SO并举了一个示例,演示了locking允许多个用户同时在表中插入行id
的情况,而不使用{ {1}}。
以下面的架构为例:
AUTO_INCREMENT
然后我们可以执行以下操作:
CREATE TABLE demo_table (id int) ENGINE=INNODB;
-- // Add few rows
INSERT INTO demo_table VALUES (1), (2), (3);
FOR UPDATE
语法实际上是锁定此查询读取的行。
如果不提交事务,我们会启动另一个单独的会话(模拟并发用户),并执行相同的操作:
START TRANSACTION;
-- // Get the MAX(id) so that we increment it by one
SELECT @x := MAX(id) FROM your_table FOR UPDATE;
+---------------+
| @x := MAX(id) |
+---------------+
| 3 |
+---------------+
1 row in set (0.00 sec)
在运行此查询之前,数据库将一直等到上一个会话中设置的锁定。
因此,切换到上一个会话,我们可以插入新行并提交事务:
START TRANSACTION;
-- // Get the MAX(id) as well
SELECT MAX(id) FROM demo_table FOR UPDATE;
第一个会话提交事务后,锁定将被解除,并返回第二个会话中的查询:
-- // Insert a new row with id = MAX(id) + 1
INSERT INTO demo_table VALUES (@x + 1);
COMMIT;
请注意,如果没有锁定,第二个会话将立即返回,但+---------+
| MAX(id) |
+---------+
| 4 |
+---------+
1 row in set (8.19 sec)
为3
而不是MAX(id)
。如果两个会话都要插入4
id
的行,则两者都会插入MAX(id) + 1
。您可以在没有id = 4
位的情况下模拟相同的测试,看看如何在没有锁的情况下处理它。