基于PostgreSQL 9.4

四、显式锁定

PostgreSQL提供了多种锁模式用于控制对表中数据的并发访问。这些模式可以用于在MVCC无法给出期望行为的场合。同样,大多数PostgreSQL命令自动施加恰当的锁以保证被引用的表在命令的执行过程中不会以一种不兼容的方式被删除或者修改。 比如,在存在其它并发操作的时候,TRUNCATE是不能在同一个表上面执行的。

要检查数据库服务器里所有当前正在被持有的锁,可以使用pg_locks系统视图。有关监控锁管理器子系统状态的更多信息,请参考章Chapter 27。

3.1表级锁:

下面的列表显示了可用的锁模式和它们被PostgreSQL自动使用的场合。你也可以用LOCK命令明确获取这些锁。两个事务在同一时刻不能在同一个表上持有相互冲突的锁。不过,一个事务决不会和自身冲突。比如,它可以在一个表上请求ACCESS EXCLUSIVE然后接着请求 ACCESS SHARE。 非冲突锁模式可以被许多事务同时持有。请特别注意有些锁模式是自冲突的(比如,在任意时刻ACCESS EXCLUSIVE模式就不能够被多个事务拥有), 但其它锁模式都不是自冲突的(比如,ACCESS SHARE可以被多个事务持有)。

表级锁LOCK TABLE命令语法:

LOCK [ TABLE ] [ ONLY ] name [ * ] [, ...] [ IN lockmode MODE ] [ NOWAIT ] 这里的lockmode可以是下列之一:

ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE

| SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE

下面是可用的锁模式和它们被PostgreSQL自动使用的场合。你也可以用LOCK命令明确获取这些锁。请注意所有这些锁模式都是表级锁,即使它们的名字包含"row"单词(这些名称是历史遗产)。从某种角度而言,这些名字反应了每种锁模式的典型用法—但是语意却都是一样的。两种锁模式之间真正的区别是它们有着不同的冲突锁集合(参见Table 13-2)。 两个事务在同一时刻不能在同一个表上持有相互冲突的锁。不过,一个事务决不会和自身冲突。比如,它可以在一个表上请求ACCESS EXCLUSIVE然后接着请求ACCESS SHARE。非冲突锁模式可以被许多事务同时持有。请特别注意有些锁模式是自冲突的(比如,在任意时刻ACCESS EXCLUSIVE模式就不能够被多个事务拥有),但其它锁模式都不是自冲突的(比如,ACCESS SHARE可以被多个事务持有)。

8大表级锁模式:

ACCESS SHARE:只与ACCESS EXCLUSIVE冲突。 SELECT命令在引用的表上请求这个锁。通常,任何只读取表而不修改它的命令都请求这种锁模式。

--事务1

BEGIN;

--给表lyy上access share锁

LOCK TABLE lyy IN ACCESS SHAER MODE;

--与SELECT * FROM lyy;产生相同类型的锁

--事务2:

BGEIN;

--给表lyy上access exclusive锁.

LOCK TABLE lyy IN ACCESS EXCLUSIVE MODE;

--与DROP TABLE lyy或者其他DDL操作产生相同类型的锁。

--以上操作被阻塞,因为产生了锁冲突

ROW SHARE:与EXCLUSIVE和ACCESS EXCLUSIVE锁模式冲突。SELECT FOR UPDATE和SELECT FOR SHARE命令在目标表上需要一个这样模式的锁 (加上在所有被引用但没有ACCESS SHARE的表上的FOR UPDATE/FOR SHARE锁)。

ROW EXCLUSIVE:与SHARE,SHARE ROW EXCLUSIVE,EXCLUSIVE和ACCESS EXCLUSIVE锁模式冲突。UPDATE,DELETE和INSERT命令自动请求这个锁模式(加上所有其它被引用的表上的ACCESS SHARE锁)。通常,这种锁将被任何修改表中数据的查询请求。

SHARE UPDATE EXCLUSIVE:与SHARE UPDATE EXCLUSIVE,SHARE,SHARE ROW EXCLUSIVE,EXCLUSIVE和ACCESS EXCLUSIVE锁模式冲突。这个模式保护一个表不被并发模式改变和VACUUM。 VACUUM(不带FULL选项),ANALYZE,CREATE INDEX CONCURRENTLY和ALTER TABLE请求这样的锁。

SHARE:与ROW EXCLUSIVE,SHARE UPDATE EXCLUSIVE,SHARE ROW EXCLUSIVE,EXCLUSIVE和ACCESS EXCLUSIVE锁模式冲突。这个模式避免表的并发数据修改。CREATE INDEX(不带CONCURRENTLY选项)语句要求这样的锁模式。

SHARE ROW EXCLUSIVE:与ROW EXCLUSIVE,SHARE UPDATE EXCLUSIVE,SHARE,SHARE ROW EXCLUSIVE,EXCLUSIVE和ACCESS EXCLUSIVE锁模式冲突。 这个模式避免表的并发数据修改。 并且是自我排斥的,因此每次只有一个会话可以拥有它。 任何PostgreSQL命令都不会自动请求这个锁模式。

EXCLUSIVE:与ROW SHARE,ROW EXCLUSIVE,SHARE UPDATE EXCLUSIVE,SHARE,SHARE ROW EXCLUSIVE,EXCLUSIVE和ACCESS EXCLUSIVE锁模式冲突。这个模式只允许并发ACCESS SHARE锁,也就是说,只有对表的读动作可以和持有这个锁模式的事务并发执行。 任何PostgreSQL命令都不会在用户表上自动请求这个锁模式。

ACCESS EXCLUSIVE:与所有模式冲突(8大模式,也包括自身类型)。这个模式保证其所有者(事务)是可以访问该表的唯一事务。 ALTER TABLE,DROP TABLE,TRUNCATE,REINDEX,CLUSTER和VACUUM FULL命令要求这样的锁。多种形式的ALTER TABLE也要求一个该级别的锁 (参见ALTER TABLE).在LOCK TABLE命令没有明确声明需要的锁模式时,ACCESS EXCLUSIVE是缺省表锁模式。

注意:只有ACCESS EXCLUSIVE阻塞SELECT(不包含FOR UPDATE/SHARE语句)。

--事务1

BEGIN;

LOCK TABLE lyy in access exclusive mode;

--事务2

BEGIN;

SELECT * FROM lyy;

--与LOCK TABLE lyy IN ACCESS SHAER MODE;都产生ACCESS SHARE锁

--SELECT操作阻塞,因为与access exclusive产生了锁冲突

一旦请求已获得某种锁,那么该锁模式将持续到事务结束。但是如果在建立保存点之后才获得锁,那么在回滚到这个保存点的时候将立即释放所有该保存点之后获得的锁。这与ROLLBACK取消所有保存点之后对表的影响的原则一致。同样的原则也适用于PL/pgSQL异常块中获得的锁:一个跳出块的错误将释放在块中获得的锁。

--事务1

postgres=# begin;

BEGIN

postgres=# LOCK TABLE lyy IN ACCESS SHARE MODE;

LOCK TABLE

postgres=# savepoint svp1;

SAVEPOINT

postgres=# LOCK TABLE lyy IN ACCESS exclusive MODE;

LOCK TABLE

--事务2

postgres=# begin;

BEGIN

postgres=# select * from lyy;--此时操作被阻塞,因为此时是ACCESS exclusive锁

--事务1

postgres=# rollback to savepoint svp1;//此时是access share锁

ROLLBACK

--事务2

此时select * from lyy返回查询结果.//access share锁不阻塞SELECT操作。

冲突锁模式对比表

Requested Lock Mode

Current Lock Mode

ACCESS SHARE

ROW SHARE

ROW EXCLUSIVE

SHARE UPDATE EXCLUSIVE

SHARE

SHARE ROW EXCLUSIVE

EXCLUSIVE

ACCESS EXCLUSIVE

ACCESS SHARE

X

ROW SHARE

X

X

ROW EXCLUSIVE

X

X

X

X

SHARE UPDATE EXCLUSIVE

X

X

X

X

X

SHARE

X

X

X

X

X

SHARE ROW EXCLUSIVE

X

X

X

X

X

X

EXCLUSIVE

X

X

X

X

X

X

X

ACCESS EXCLUSIVE

X

X

X

X

X

X

X

X

备注: 上图是Postgresql 表级锁的各种冲突模式对照表,‘X’表示冲突项。

3.2行级锁:

行级锁可以是排他的或者是共享的。特定行上的排他行级锁是在行被更新的时候自动请求的。 该锁一直保持到事务提交或者回滚。行级锁不影响对数据的查询,它们只阻塞对同一行的写入。

行级锁(SELECT .. FOR ..)命令语法

FOR UPDATE,FOR NO KEY UPDATE,FOR SHARE和FOR KEY SHARE是锁定子句;他们影响SELECT如何从表中锁定行作为获得的行。锁定子句的一般形式:

FOR lock_strength [ OF table_name [, ...] ] [ NOWAIT ]

这里的lock_strength可以是下列之一:

UPDATE

NO KEY UPDATE

SHARE

KEY SHARE

4个行级锁强度

FOR UPDATE:令那些被SELECT检索出来的行被锁住,就像在更新一样。这样就避免它们在当前事务结束前被其它事务修改或者删除;也就是说, 其它企图UPDATE,DELETE,SELECT FOR UPDATE,SELECT FOR NO KEY UPDATE,SELECT FOR SHARE或SELECT FOR KEY SHARE这些行的事务将被阻塞,直到当前事务结束。同样, 如果一个来自其它事务的UPDATE,DELETE,SELECT FOR UPDATE已经锁住了某个或某些选定的行,SELECT FOR UPDATE将等到那些事务结束,并且将随后锁住并返回更新的行(或者不返回行,如果行已经被删除)。但是,在REPEATABLE READ或SERIALIZABLE事务内部,如果在事务开始时要被锁定的行已经改变了,那么将抛出一个错误。更多的讨论参阅Chapter 13。

FOR NO KEY UPDATE的行为类似于FOR UPDATE,只是获得的锁比较弱:该锁不阻塞尝试在相同的行上获得锁的SELECT FOR KEY SHARE命令。该锁模式也可以通过任何不争取FOR UPDATE锁的UPDATE获得。

FOR SHARE的行为类似于FOR NO KEY UPDATE,只是它在每个检索出来的行上获得一个共享锁,而不是一个排它锁。一个共享锁阻塞其它事务在这些行上执行UPDATE,DELETE,SELECT FOR UPDATE或SELECT FOR NO KEY UPDATE,却不阻止他们执行SELECT FOR SHARE或SELECT FOR KEY SHARE。

FOR KEY SHARE的行为类似于FOR SHARE,只是获得的锁比较弱: 阻塞SELECT FOR UPDATE但不阻塞SELECT FOR NO KEY UPDATE。一个共享锁阻塞其他事务执行DELETE或任意改变键值的UPDATE, 但是不阻塞其他UPDATE,也不阻止SELECT FOR NO KEY UPDATE, SELECT FOR SHARE 或SELECT FOR KEY SHARE。

为了避免操作等待其它事务提交,使用NOWAIT选项。如果被选择的行不能立即被锁住, 那么语句将会立即汇报一个错误,而不是等待。请注意,NOWAIT只适用于行级别的锁, 要求的表级锁ROW SHARE仍然以通常的方法进行(参阅Chapter 13)。 如果需要申请表级别的锁同时又不等待,那么你可以使用LOCK的NOWAIT选项。

举例说明:

准备表和数据:

CREATE TABLE lyy(id int primary key, name varchar);

INSERT INTO lyy values(1,'a1'),(2,'a2'),(3,'a3'),(4,'a4');

--for update

事务1:

BEGIN;

SELECT * FROM lyy WHERE id<3 FOR UPDATE;

事务2:

BEGIN;

UPDATE lyy SET name='aa' WHERE id=2;

--此时id=2的行已被FOR UPDATE锁定,所以update操作阻塞,直到事务1,提交之后,才能执行。

--for no key update

事务1:

BEGIN;

SELECT * FROM lyy WHERE id=1 FOR NO KEY UPDATE;

--在对行1的锁定效果上,等价于

update lyy set id=2 where id=2;

事务1:

BEGIN;

SELECT * FROM lyy WHERE id=1 FOR KEY SHARE;

--该行可以执行,因为虽然id=1的行已被锁定,但是FOR NO KEY UPDATE不阻塞SELECT ... FOR KEY SHARE;

--for share

事务1:

BGEIN;

SELECT * FROM lyy WHERE id=1 FOR SHARE;

事务2:

BEGIN;

SELECT * FROM lyy WHERE id=1 FOR [KEY] SHARE;--可以执行,因为该行的FOR SHARE锁,不阻塞FOR [KEY] SHARE;

UPDATE lyy set name='sss' WHERE id=1; --阻塞,

--for key share

事务1:

BGEIN;

SELECT * FROM lyy WHERE id=1 FOR KEY SHARE;

事务2:

BEGIN;

UPDATE lyy SET id=222 WHERE id=2; --阻塞,for key share 阻塞键值字段的update操作;

UPDATE lyy SET name='coco' WHERE id=2; --正常执行,for update share不阻塞非键值字段的update操作。

3.3页级锁

除了表级锁和行级锁,页级别的共享/排他锁用来控制中对表页的读/写访问(在共享缓存池)。一个行被抓去或者更新后,这些锁会迅速被释放。应用开发者通常不需要关心页级锁,在此处提及页级锁是为了锁机制介绍的完整性。

3.4死锁:

显式锁定的使用可能会增加死锁的可能性。

死锁是指两个(或两个以上)事务相互持有对方期待的锁,如果没有其他机制,这些事务都将无法进行下去。

避免死锁的方法

防止死锁的最好方法通常是保持所有使用同一个数据库的应用都能与相同的顺序在多个对象上请求排它锁。

由于数据库可以自动检测出死锁,所以应用也可以通过补货死锁异常来处理思索。但这不是一个很好的方法,因为数据库检测死锁需要一些代价,可能会导致应用程序过久持有排它锁,从而导致系统的并发处理能力下降。

排它锁持有的时间越长,就越容易导致死锁,所以在程序设计时,要尽量短的持有排它锁。

阻塞与死锁的区别

数据库阻塞的现象: 第一个连接占有资源没有释放,而第二个连接需要获取这个资源。如果第一个连接没有提交或者回滚,第二个连接会一直等待下去,直到第一个连接释放该资源为止。对于阻塞,数据库无法处理,所以对数据库操作要及时地提交或者回滚。

数据库死锁的现象:第一个连接占有资源没有释放,准备获取第二个连接所占用的资源,而第二个连接占有资源没有释放,准备获取第一个连接所占用的资源。这种互相占有对方需要获取的资源的现象叫做死锁。对于死锁,数据库处理方法:牺牲一个连接,保证另外一个连接成功执行。

3.5咨询锁:

PostgreSQL允许创建由应用定义其含义的锁。这种锁被称为咨询锁, 因为系统并不强迫其使用— 而是由应用来保证其被恰当的使用。 咨询锁可用于 MVCC 难以实现的锁定策略。 比如,咨询锁一般用于模拟常见于"平面文件"数据管理系统的悲观锁策略。 虽然可以用存储在表中的一个特定标志达到同样的目的,但是使用咨询锁更快,还可以避免表臃肿, 更可以在会话结束的时候由系统自动执行清理工作。

postgresql 并发访问_PostgreSQL并发控制(显式锁定)相关推荐

  1. postgresql 并发访问_postgresql 并发update下导致的死锁问题

    一.死锁问题背景 在收据批量打印时,由于采用异步并发触发打印,同时触发打印(九千多数据 每隔50ms触发一次),导致了并发执行引起在接口更新打印次数时postgresql发生死锁问题, 具体报错如下: ...

  2. 连续锁定2个不同的锁会死锁_研究死锁–第5部分:使用显式锁定

    连续锁定2个不同的锁会死锁 在我的上一个博客中,我研究了使用Java的传统synchronized关键字和锁排序来修复破碎的,死锁的余额转移示例代码. 但是,有另一种方法称为显式锁定. 在这里,将锁定 ...

  3. 研究死锁–第5部分:使用显式锁定

    在我的上一个博客中,我研究了使用Java的传统synchronized关键字和锁排序来修复破碎的,死锁的余额转移示例代码. 但是,有一种替代方法称为显式锁定. 这里,将锁定机制称为显式而非隐式的想法是 ...

  4. [MySQL] mysql 的行级显式锁定和悲观锁

    [MySQL] mysql 的行级显式锁定和悲观锁 隐式和显式锁定: 1.innodb是两阶段锁定协议,隐式锁定比如在事务的执行过程中.会进行锁定,锁只有在commit或rollback的时候,才会同 ...

  5. 存储过程 锁定并发_Java并发教程–锁定:显式锁定

    存储过程 锁定并发 1.简介 在许多情况下,使用隐式锁定就足够了. 有时,我们将需要更复杂的功能. 在这种情况下, java.util.concurrent.locks包为我们提供了锁定对象. 当涉及 ...

  6. Java并发教程–锁定:显式锁定

    1.简介 在许多情况下,使用隐式锁定就足够了. 有时,我们将需要更复杂的功能. 在这种情况下, java.util.concurrent.locks包为我们提供了锁定对象. 当涉及到内存同步时,这些锁 ...

  7. java 中的锁 aqs_Java并发编程系列-(4) 显式锁与AQS

    4 显示锁和AQS 4.1 Lock接口 核心方法 Java在java.util.concurrent.locks包中提供了一系列的显示锁类,其中最基础的就是Lock接口,该接口提供了几个常见的锁相关 ...

  8. java 可重入锁 clh_Java并发编程系列-(4) 显式锁与AQS

    4 显示锁和AQS 4.1 Lock接口 核心方法 Java在java.util.concurrent.locks包中提供了一系列的显示锁类,其中最基础的就是Lock接口,该接口提供了几个常见的锁相关 ...

  9. 构造函数调用默认构造函数_显式无参数构造函数与默认构造函数

    构造函数调用默认构造函数 大多数不熟悉Java的开发人员都会Swift了解到,如果他们没有指定至少一个显式构造函数,则会为Java类隐式创建一个" 默认构造函数 "( 由javac ...

最新文章

  1. SAP PM 初级系列3 - 主数据相关的基础设置
  2. 向uliweb中添加查找配置项功能
  3. 线程池配置合理线程数?
  4. ubantu 安装杀毒软件 clamav
  5. 【并发那些事】可见性问题的万恶之源
  6. go 并发安全map 分段锁实现
  7. 2020-08-07 光纤通信第二章知识点整理
  8. python读取csv最后一行_python – 尝试使用seek()获取csv文件的最后一行时的AttributeError...
  9. 鸿蒙系统新手教程,鸿蒙灭神决新手入门全流程图文攻略
  10. Python 面向对象(二)
  11. 我也谈谈代码的性能测试及代码改进
  12. python迭代对象有哪些_Python可迭代对象操作示例
  13. 静态编译和动态编译的区别【转】
  14. 【交通标志识别】基于matlab GUI矩匹配算法路标识别【含Matlab源码 1175期】
  15. 焦作哪里有学机器人编程_焦作自学plc入门梯形图编程去哪学
  16. js 让鼠标右下角有一排小字_JS实现跟随鼠标的链接文字提示框效果
  17. 游戏设计---游戏中战斗力计算方法(整理)
  18. Your system is infected with 3 viruses!(您的系统感染了3种病毒!)
  19. vue内使用 cytoscape(数据可视化)
  20. c4droid入门教程 2021.2.6更新

热门文章

  1. struts2中的method
  2. 委托与事件-闲聊系列(二)
  3. Hyper-V passes Microsoft’s checkmarks exam: isn’t that always the case?
  4. 判断java String中是否有汉字的方法
  5. 安装redis3.2.4集群时出现的一些坑
  6. 如何学计算机课程,一张图告诉你大学如何学好计算机专业课程
  7. 计算机组成原理笔记第十章笔记整理
  8. 输入n种口味随机输出四种不同的口味!
  9. Load Balance System
  10. puppet3.5源码包安装和配置