什么是MySQL中的锁定(或任何关系型数据库),在什么情况下会使用它?通过示例来进行生动易懂的解释最好不过了!
我们有一个联合银行账户,余额为200美元
我去自动取款机,把卡插进机器里,机器检查到我的余额是200美元
同时,你走进银行要求50美元,出纳员查看你的账户并确认你有这笔钱。
我请求提取200美元,机器计算出我的钞票,给了我200美元,并将我的余额设置为0
出纳员清点你的钱并给你50美元,然后系统更新账户余额为150美元(200美元 - 50美元提款)。
现在我们手头上有250美元现金和150美元的账户余额。 200美元的利润。
数据库应该使用锁来防止两个交易同时发生。
问题是,如果每个交易都以这种方式处理,那么我们会失去并发性,并且性能会受到影响,因此根据情况使用不同的“事务隔离级别”,例如您可能不关心某人可以修改在事务中已读取的数据。
http://en.wikipedia.org/wiki/Isolation_%28database_systems%29
您应该学习并了解适用的方案。
AUTO_INCREMENT
的情况下,锁定允许多个用户同时向具有递增id
的表中插入行的情况。CREATE TABLE demo_table (id int) ENGINE=INNODB;
-- // Add few rows
INSERT INTO demo_table VALUES (1), (2), (3);
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)
FOR UPDATE
语法实际上是在此查询中对读取的行加锁。
在不提交事务的情况下,我们启动另一个独立的会话(模拟并发用户),并执行相同的操作:
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)
MAX(id)
的值为3
而不是4
。如果两个会话都插入一个id = MAX(id) + 1
的行,则两者都将插入id = 4
。您可以模拟相同的测试,而不使用FOR UPDATE
,以了解在没有锁定的情况下如何处理此问题。