CodeGym /课程 /SQL SELF /事务操作中的限制和潜在问题:LOCK,DEADLOCK

事务操作中的限制和潜在问题:LOCK,DEADLOCK

SQL SELF
第 54 级 , 课程 1
可用

事务操作中的限制和潜在问题:LOCKDEADLOCK

PostgreSQL里的事务保证了隔离性——这是ACID的一个关键特性。为此,系统会用到锁。锁就是一种机制,保证多个事务不会“抢”同一条记录或表。你可以想象超市排队结账:收银台一次只服务一个人。锁的作用差不多,就是用来管理表里数据的访问。

锁的主要类型

PostgreSQL有几种锁类型,有些你可能已经在EXPLAIN ANALYZE里见过:

  1. ROW EXCLUSIVE(行级排他锁)——当你修改某行数据时会用到。这是最常见的锁类型,比如执行INSERTUPDATEDELETE时。
  2. SHARE(共享锁)——用于保证在查询执行期间数据不会被改动,比如SELECT ... FOR SHARE
  3. EXCLUSIVE(排他锁)——阻止除了读以外的所有其他操作。

可以说,锁就像看门狗一样,守护着我们的数据。

锁的问题:可能会出啥岔子?

现在我们知道锁是啥了,来看看它们可能带来的问题。最大的问题就是死锁。死锁(deadlock)就是两个(或更多)事务互相等待对方释放资源,结果大家都卡住了,进了死循环。一般是这样:

  1. 事务1锁住了行A,想要访问行B。
  2. 事务2锁住了行B,想要访问行A。
  3. 因为两行都被锁住了,两个事务都没法完成。

死锁的例子

想象一下程序员遇到死锁的痛苦,场景如下:

-- 事务1
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- 同时
-- 事务2
BEGIN;
UPDATE accounts SET balance = balance + 200 WHERE id = 2;

-- 事务1试图锁id = 2
UPDATE accounts SET balance = balance - 100 WHERE id = 2;

-- 事务2试图锁id = 1
UPDATE accounts SET balance = balance + 200 WHERE id = 1;

瞧!每个事务都被另一个锁住了。PostgreSQL迟早会发现这个问题,然后抛出死锁错误

怎么避免死锁?

  1. 数据访问顺序要一致。 尽量总是按同样的顺序访问数据。如果事务1先锁A再锁B,那事务2也应该先锁A再锁B。
-- 正确的数据访问顺序
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 200 WHERE id = 2;
COMMIT;
  1. 尽量缩短事务持续时间。 事务时间越长,死锁的概率越高。尽快完成事务:BEGIN,做完所有需要的更改,然后立刻COMMIT

  2. 用合适的事务隔离级别。 如果你的需求不需要很严格的数据隔离,可以考虑用READ COMMITTED隔离级别。这样能避免一些锁。

锁的超时和诊断

PostgreSQL有工具可以诊断和预防锁问题。比如,你可以设置锁的最大等待时间:

SET lock_timeout = '5s';  -- 把锁超时设置为5秒

如果锁被持有超过这个时间,事务就会被中断,这样就不会彻底卡死了。

PostgreSQL里怎么监控锁

一个很有用的监控锁的命令是pg_locks。它能显示系统里所有的活动锁:

SELECT * FROM pg_locks;

你可以看到哪些事务持有锁,哪些在等锁。调试死锁的时候特别有用。

LOCK的特点和手动锁定对象

如果你需要手动管理锁,可以用LOCK命令:

LOCK TABLE orders IN ACCESS EXCLUSIVE MODE;

注意:ACCESS EXCLUSIVE是最强的锁,会禁止对表的所有其他操作,连SELECT都不行。只有在特殊情况下(比如改表结构)才用它。

如果你只想锁定某几行,可以用SELECT ... FOR UPDATE

SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

这样可以保证在你的事务结束前,其他事务不能改这些行。

关于锁你要记住啥?

锁不是坏东西,而是工具。它们帮你保证数据完整性,但用的时候要小心。给你几个建议:

  1. 没想好为啥要用事务就别开事务。
  2. 事务要尽快结束。
  3. 避免用不同的顺序访问数据。
  4. 用适合你需求的隔离级别。

现在你已经准备好和锁、死锁打交道啦!祝你用pg_locks顺利,ACID智慧常伴你身边。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION