随着多用户数据库的出现,限制同时修改相同数据的任务变得至关重要。这导致了各种锁定机制(锁管理)的出现,这些机制防止并行修改并有助于维护数据的完整性。
如果没有访问控制,同时操作可能导致数据损坏或丢失:例如,两个事务同时更新一行,一笔事务的更改会丢失。不够严格的锁定会导致竞争问题(竞争条件),而过多的锁定会导致性能损失(死锁、争用)。
在现代DBMS中,存在锁定级别(行级、页级、表级)和不同的模式(共享、排他、更新)。程序员可以通过事务隔离设置和显式锁定命令(例如,SELECT ... FOR UPDATE)来管理这一点。
代码示例:
-- 在事务完成之前锁定行 BEGIN TRANSACTION; SELECT * FROM users WHERE id = 1 FOR UPDATE; UPDATE users SET name = '新名称' WHERE id = 1; COMMIT;
关键特点:
共享锁(共享锁)和排他锁(排他锁)之间有什么区别?
共享锁允许多个事务同时读取数据,但不允许修改。排他锁仅允许一个事务修改数据,其他所有事务都被禁止访问。
SELECT命令能否引发锁定?
通常,SELECT不会引发锁定,但如果使用SELECT ... FOR UPDATE或者在高隔离级别(例如,SERIALIZABLE)下,DBMS可能会锁定行。
代码示例:
SELECT * FROM products WHERE id = 10 FOR UPDATE;
锁定是否总能防止“丢失的更新”?
不可以,如果锁定或隔离级别选择不当,可能会导致“丢失更新”——即一笔事务的更改因另一笔事务而丢失。需要仔细选择并发控制机制。
在分析部门,两款程序同时更新订单状态。为了加快速度,特意设置了READ UNCOMMITTED级别,以避免锁定行。结果导致冲突和“丢失”的更新,部分数据损坏。
优点:
缺点:
在销售部门,关键位置采用了TRANSACTION + SELECT ... FOR UPDATE。将读取和更新操作在行级别上区分开。
优点:
缺点: