数据库并发事务控制四:postgresql数据库的锁机制二:表锁

在博文《数据库并发事务控制四:postgresql数据库的锁机制 》

http://blog.csdn.net/beiigang/article/details/43302947

中后面提到:

常规锁机制可以参考pg的官方手册,章节和内容见下面

13.3. Explicit Locking

http://www.postgresql.org/docs/9.4/static/explicit-locking.html

这节分为:表锁、行锁、页锁、死锁、Advisory锁(这个名字怎么翻译好??? 忠告锁,公告锁,咨询锁???)。

后面的内容提纲就是:

表锁、

行锁、

页锁、

死锁、

Advisory锁(这个名字怎么翻译好??? 忠告锁,公告锁,咨询锁???)、

查看锁。

感觉有些累了,懒了,不想写了,后面看情况到网上找些同仁同志同学朋友们的文章,放到这儿归类,如有需要待下次按我的思路再整理组织,今次先把题目做完整吧。

这儿继续,下面的内容转自下面,只是小改了几处手误的地方,把第三节的图换成了官网上的

http://francs3.blog.163.com/blog/static/40576727201082134343604/

原文标题:Postgresql 锁浅析

一、概述

此文档主要对Postgresql 锁机制进行分析,在讲解的过程中结合实验,理解Postgresql的锁机制。

二、表级锁类型

表级锁类型分为八种,以下对各种表级锁类型进行简单介绍下, 锁的冲突模式可以参考3.1的图一:表级锁冲突模式。

2.1 ACCESS SHARE

“ACCESS SHARE”锁模式只与“ACCESS EXCLUSIVE” 锁模式冲突;

查询命令(Select command)将会在它查询的表上获取”Access Shared” 锁,一般地,任何一个对表上的只读查询操作都将获取这种类型的锁。

2.2 ROW SHARE

“Row Share” 锁模式与”Exclusive’和”Access Exclusive”锁模式冲突;

”Select for update”和”Select for share”命令将获得这种类型锁,并且所有被引用但没有 FOR UPDATE 的表上会加上”Access shared locks”锁。

2.3 ROW EXCLUSIVE

“Row exclusive” 与 “Share,Shared roexclusive,Exclusive,Access exclusive”模式冲突;

“Update,Delete,Insert”命令会在目标表上获得这种类型的锁,并且在其它被引用的表上加上”Access shared”锁,一般地,更改表数据的命令都将在这张表上获得”Row exclusive”锁。

2.4 SHARE UPDATE EXCLUSIVE

”Share update exclusive,Share,Share row ,exclusive,exclusive,Access exclusive”模式冲突,这种模式保护一张表不被并发的模式更改和VACUUM;

“Vacuum(without full), Analyze ”和 “Create index concurrently”命令会获得这种类型锁。

2.5 SHARE

与“Row exclusive,Shared update exclusive,Share row exclusive ,Exclusive,Access exclusive”锁模式冲突,这种模式保护一张表数据不被并发的更改;

“Create index”命令会获得这种锁模式。

2.6 SHARE ROW EXCLUSIVE

与“Row exclusive,Share update exclusive,Shared,Shared row exclusive,Exclusive,Access Exclusive”锁模式冲突;

任何Postgresql 命令不会自动获得这种锁。

2.7 EXCLUSIVE

与” ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, ACCESS EXCLUSIVE”模式冲突,这种索模式仅能与Access Share 模式并发,换句话说,只有读操作可以和持有”EXCLUSIVE”锁的事务并行;

任何Postgresql 命令不会自动获得这种类型的锁;

2.8 ACCESS EXCLUSIVE

与所有模式锁冲突(ACCESS SHARE, ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, and ACCESS EXCLUSIVE),这种模式保证了当前只有一个事务访问这张表;

“ALTER TABLE, DROP TABLE, TRUNCATE, REINDEX, CLUSTER, VACUUM FULL” 命令会获得这种类型锁,在Lock table 命令中,如果没有申明其它模式,它也是缺省模式。

三、表级锁冲突模式

3.1  Conflicting lock modes

Table 13-2. Conflicting Lock Modes

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

备注: 上图是pg 表级锁的各种冲突模式对照表,‘X’表示冲突项, 在章节四中会对其中典型的锁模式进行模似演示。

四、实验

在这一章节中将会对图一中比较典型的锁冲突进行模似演练,了解这些在Postgresql DBA的日常维护工作中很有帮助,同时也能减少人为故障的发生。

4.1  Access exclusive 锁与Access share锁冲突

在日常维护中,大家应该执行过’ALTER TABLE’更改表结构的DDL,例如加字段,更改字段数据类型等,根据章节二的理论,在执行’ALTER TABLE’命令时将申请一个Access exclusive锁, 根据图一,大家知道Access exclusive 锁和所有的锁模式都冲突,那么,它将会’Select’命令冲突,因为Select 加的是Access share锁,那么真的会与‘SELECT‘命令冲突吗,接下来给大家演示下:

--创建一张测试表 test_2 并插入测试数据

mydb=> create table test_2 (id integer,name varchar(32));

CREATE TABLE

mydb=> insert into test_2 values (1,‘franc‘);

INSERT 0 1

mydb=> insert into test_2 values (2,‘tan‘);

INSERT 0 1

mydb=> select * from test_2;

id | name

----+-------

1 | franc

2 | tan

(2 rows)

--会话一 查询表数据 ( 这里获得Access Shared 锁)

mydb=> begin;

BEGIN

mydb=> select * from test_2 where id=1;

id | name

----+-------

1 | franc

(1 row)

注意:这里begin开始事务,没有提交;

--会话二 更改表结构 (这里申请 Access Exclusive锁 )

mydb=> alter table test_2 add column sex char(1);

发现,命令一直等侍,执行不下去;

--会话三 查询状态

mydb=# select oid,relname from pg_class where relname=‘test_2‘;

oid  | relname

-------+---------

33802 | test_2

mydb=# select locktype,database,relation,pid,mode from pg_locks where relation=‘33802‘;

locktype | database | relation |  pid  |        mode

----------+----------+----------+-------+---------------------

relation |    16466 |    33802 | 18577 | AccessShareLock

relation |    16466 |    33802 | 18654 | AccessExclusiveLock

mydb=# select datname,procpid,usename,current_query from pg_stat_activity where procpid in (18577,18654);

datname | procpid | usename |               current_query

---------+---------+---------+--------------------------------------------

mydb    |   18577 | skytf   | <IDLE> in transaction

mydb    |   18654 | skytf   | alter table test_2 add column sex char(1);

(2 rows)

这里可以看出会话一(pid=18577) 获取的是 “AccessShareLock”锁,

会话二(pid=18654 ) 获取的是 “AccessExclusiveLock”锁。

--再次回到会话一,执行‘end‘结束事务后会发生什么结果

注意,此时会话二还处于等侍状态

mydb=> end;

COMMIT

--回到会话二发现 原来处于等侍状态的‘ALTER TABLE‘命令执行成功

mydb=> alter table test_2 add column sex char(1);

ALTER TABLE

mydb=> \d test_2

Table "skytf.test_2"

Column |         Type          | Modifiers

--------+-----------------------+-----------

id     | integer               |

name   | character varying(32) |

sex    | character(1)          |

--回到会话三,锁已经释放

mydb=# select locktype,database,relation,pid,mode from pg_locks where relation=‘33802‘;

locktype | database | relation | pid | mode

----------+----------+----------+-----+------

(0 rows)

mydb=# select datname,procpid,usename,client_addr,current_query from pg_stat_activity where procpid in (18577,18654);

datname | procpid | usename | client_addr | current_query

---------+---------+---------+-------------+---------------

mydb    |   18577 | skytf   |             | <IDLE>

mydb    |   18654 | skytf   |             | <IDLE>

(2 rows)

实验说明: 这个实验说明了 ‘ALTER TABLE‘命令与‘SELECT‘命令会产生冲突,证实了开始的结论,即"Access exclusive"锁模式与申请"Access shared"锁模式的‘SELECT‘命令相冲突。

4.2  Share 锁与 Row Exclusive 锁冲突

在数据库的维护过程中,创建索引也是经常做的工作,别小看创建索引,如果是一个很繁忙的系统,索引不一定能创建得上,可能会发生等侍, 严重时造成系统故障;根据章节二的理论,’Create Index’ 命令需要获取Share 锁模式。

根据图一,”Share” 锁和”Row Exclusive”锁冲突,下面来验证一下:

根据图一可以看出,share锁模式和多种锁模式冲突,有可能会问我,为什么单独讲share锁和Row Exclusive冲突呢?因为” Update,Delete,Insert”命令获取的是Row Exclusive 操作,而这种操作在生产过程中非常频繁;这个实验正是模似生产维护过程。

--会话一, 向 test_2 上插入一条数据

mydb=> select * from test_2;

id | name  | sex

----+-------+-----

1 | franc |

2 | tan   |

(2 rows)

mydb=> begin;

BEGIN

mydb=> insert into test_2 values (3,‘fpzhou‘);

INSERT 0 1

mydb=>

说明: 这个Insert 操作放在一个事务里,注意此时事务尚未提交。

--会话二,在表test_2上创建索引

mydb=> \d test_2;

Table "skytf.test_2"

Column |         Type          | Modifiers

--------+-----------------------+-----------

id     | integer               |

name   | character varying(32) |

sex    | character(1)          |

mydb=> create unique index idx_test_2_id  on test_2 (id);

说明: 创建索引命令发生等侍

--会话三,查询状态

mydb=# select locktype,database,relation,pid,mode from pg_locks where relation=‘33802‘;

locktype | database | relation |  pid  |       mode

----------+----------+----------+-------+------------------

relation |    16466 |    33802 | 18577 | RowExclusiveLock

relation |    16466 |    33802 | 18654 | ShareLock

(2 rows)

mydb=# select datname,procpid,usename,client_addr,current_query from pg_stat_activity where procpid in (18577,18654);

datname | procpid | usename | client_addr |                   current_query

---------+---------+---------+-------------+----------------------------------------------------

mydb    |   18577 | skytf   |             | <IDLE> in transaction

mydb    |   18654 | skytf   |             | create unique index idx_test_2_id  on test_2 (id);

说明:  这里可以看出"Insert into"(procpid=18577) 命令获取"RowExclusiveLock”,而"Create Index"(procpid=18654)操作获取的是"Sharelock", 并且创建索引操作发了等侍,因为这两种锁模式是冲突的。

--回到会话一,提交事务,看看会发生什么

注意,此时创建索引的会话二仍处于等侍状态

mydb=> end;

COMMIT

--回到会话二,发现创建索引命令成功,等侍消失

mydb=> create unique index idx_test_2_id  on test_2 (id);

CREATE INDEX

实验结论:1 上述实验说明 "Create index "操作和"Insert"操作冲突;也就是 "Share"锁和"RowExclusive"锁冲突。

2 在生产库上应该避免在业务高峰期执行新建索引操作,因为如果在张大表上新建索引,消耗时间较长,在这个过程中会阻塞业务的DML操作。

4.3  SHARE UPDATE EXCLUSIVE 与自身冲突

根据章节二,大家知道 VACUUM(Without full), Analyze 和 Create index (Concurently)操作会申请获得”Shared update Exclusive 锁”。根据图一,”Shared update Exclusive 锁”与本身也是会冲突的,下面实验验证一下:

--会话一,分析表test_2

mydb=> select * from test_2;

id |  name  | sex

----+--------+-----

1 | franc  |

2 | tan    |

3 | fpzhou |

(3 rows)

mydb=>

mydb=>

mydb=> begin;

BEGIN

mydb=> analyze test_2;

ANALYZE

注意: 表分析放在一个事务里,此时并没有提交;

--会话二 对表 test_2 做 vacuum

mydb=> \d test_2;

Table "skytf.test_2"

Column |         Type          | Modifiers

--------+-----------------------+-----------

id     | integer               |

name   | character varying(32) |

sex    | character(1)          |

Indexes:

"idx_test_2_id" UNIQUE, btree (id)

mydb=> vacuum test_2;

注意: 当对表 test_2 执行 vacuum操作时,操作等侍,

--会话三,观察系统哪里锁住了

[[email protected] ~]$ psql -d mydb

psql (9.0beta3)

Type "help" for help.

mydb=# select datname,procpid,waiting,current_query from pg_stat_activity where waiting=‘t‘;

datname | procpid | waiting | current_query

---------+---------+---------+----------------

mydb    |   20625 | t       | vacuum test_2;

(1 row)

这里说明会话 vacuum test_2 在等侍

mydb=# select oid,relname from pg_class where relname=‘test_2‘;

oid  | relname

-------+---------

33802 | test_2

(1 row)

mydb=# select locktype,database,relation,pid,mode from pg_locks where relation=‘33802‘;

locktype | database | relation |  pid  |           mode

----------+----------+----------+-------+--------------------------

relation |    16466 |    33802 | 20625 | ShareUpdateExclusiveLock

relation |    16466 |    33802 | 20553 | ShareUpdateExclusiveLock

(2 rows)

说明: 这里可以看出 ‘Analyze‘操作 (pid=20553) 和‘Vacuum‘操作 (pid=20625)都是加的"ShareUpdateExclusiveLock"。

mydb=# select datname,procpid,waiting,current_query from pg_stat_activity where procpid in (20625,20553);

datname | procpid | waiting |     current_query

---------+---------+---------+-----------------------

mydb    |   20553 | f       | <IDLE> in transaction

mydb    |   20625 | t       | vacuum test_2;

(2 rows)

说明: 结束上面查询可以看出会话20625在等侍会话20553,也就是说"vacuum test_2" 被事务堵住了,

--再次回到会话一,提交会话,注意此时会话二处于等侍姿态;

mydb=> end;

COMMIT

--再次回到会话二,发现 vacuum命令执行下去了,等侍消失。

mydb=> vacuum test_2;

VACUUM

mydb=>  select datname,procpid,waiting,current_query from pg_stat_activity where waiting=‘t‘;

datname | procpid | waiting | current_query

---------+---------+---------+---------------

(0 rows)

实验结论 1 Analyze 和 Vacuum 操作都会申请获得 "ShareUpdateExclusiveLock"。

2 ShareUpdateExclusiveLoc与ShareUpdateExclusiveLock是冲突的。

-----------------

转载请著明出处:

blog.csdn.net/beiigang

时间: 2024-12-13 14:20:23

数据库并发事务控制四:postgresql数据库的锁机制二:表锁的相关文章

数据库并发事务控制四:postgresql数据库的锁机制

并发控制是DBMS的关键技术,并发控制技术也称为同步机制,其实现通常依赖于底层的并发控制机制.操作系统提供了多种同步对象,如事件 Event.互斥锁 Mutex和条件变量 Cond.信号量Semaphore.读写锁 RWLock.自旋锁 Spinlock等.数据库管理系统自己实现封锁主要是考虑: 锁语义加强:OS只提供排它锁.为了提高并发度,数据库至少需要共享锁和排它锁,即读锁和写锁: 锁的功能增强:数据库提供视图监测封锁情况和进行死锁检测: 可靠性的考虑:例如,在某个持锁进程任意一点回滚时,数

数据库并发事务控制 一:综述

并发控制是DBMS的关键技术 对数据库的操作都是在事务中进行的. 事务是指一组相互依赖的操作行为.事务中的操作是不可分割的工作单元,由一组在业务逻辑上相互依赖的SQL语句组成,有ACID特征. Atomic(原子性):事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败. Consistency(一致性):只有合法的数据可以被写入数据库,否则事务应该将其回滚到最初状态. Isolation(隔离性):事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完

数据库 之 事务控制和隔离级别

1  概述 事务是指一组原子性的SQL查询.或者是一个或多个SQL语句组成的独立工作单元:MyISAM不流行的原因很大是因为其不支持事务的处理功能. 2  事务日志 事务日志定义属性,有些参数可以运行时修改,写入在配置段里,事务日志相当于是中间的辅助功能,而且很关键. 事务日志表示把操作过程一笔一笔记录下来.如某个线程要对某个行操作,数据库会先保留老版本于事务日志中,对文件的写入,新版本的内容是先写入到日志里,提交前,数据在日志文件中,而不是在数据文件中,提交操作执行后,才将新旧版本的日志清除.

数据库为什么需要锁机制?有哪些锁机制?

[为什么要锁] 数据库是一个多用户使用的共享资源,比如一个用户表t_user,两个浏览器前面的人登录了同个一个账号,把电话号码改了.当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性(脏读,不可重复读,幻读等),可能产生死锁.为了解决这个问题,加锁是一个非常重要的技术,对实现数据库并发控制是一个好的方案.简单说,当一个执行sql语句的事务想要操作表记录之前,先向数据库发出请求,对你访问的记录集加锁,

数据库并发事务存在的三个问题(脏读、不可重复读、幻读)

如果不考虑事务隔离性,可能会发生以下情况 脏读:事务a,读到了事务b未提交的数据,如果事务a读到了事务b的一些中间数据,待处理的数据.b事务数据还没有提交,就被a事务访问了 (解决方法:将 读未提交 级别提高到 读已提交 例如:orale在事务a 更新t表的时候,表t为锁住的状态,事务a未提交之前,事务b就不能访问t表) 不可重复读:指的是事务两次读取数据不一样.因为中间被其他事务修改了.解决方法就是 将 级别提高到 可重复.使用行级锁,锁定当前记录,其它事务无法更改.针对update操作 幻读

数据库之事务并发问题与事务的隔离级别

事物的并发问题: 事物的并发问题主要分四个方面,即丢失更新,脏读,不可重复读,幻读.如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时,则可能会发生以上几种问题. 1.丢失更新 当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题.每个事务都不知道其它事务的存在.最后的更新将重写由其它事务所作的更新,这样就会导致数据丢失.丢失更新可分为两类: 第一类丢失更新 例如: 时 间   取款事务                             

数据库事务、事务隔离级别以及锁机制详解

以下主要以MySQL(InnoDB引擎)数据库为讨论背景,纯属个人学习总结,不对的地方还请指出! 什么是事务? 事务是作为一个逻辑单元执行的一系列操作,要么一起成功,要么一起失败.一个逻辑工作单元必须有四个属性,称为 ACID(原子性.致性.隔离性和持久性)属性,只有这样才能成为一个事务. 数据库事物的四大特性(ACID): 1)原子性:(Atomicity) 务必须是原子工作单元:对于其数据修改,要么全都执行,要么全都不执行. 2)一致性:(Consistency) 事务在完成时,必须使所有的

数据库的事务

数据库事务:事务是数据库运行中的一个逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理. 以下内容部分介绍转自用户fjdingsd: 数据库支持事务的操作的数据库特性(ACID): ⑴ 原子性(Atomicity)原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响. ⑵ 一致性(Consistency)一致性是指事务必须使数据库从一个一致性状态变换到另一

Linux命令应用大词典-第42章 PostgreSQL数据库

42.1 initdb:初始化PostgreSQL数据库 42.2 pg_ctl:控制PostgreSQL服务 42.3 psql:PostgreSQL交互式客户端工具 42.4 createdb:创建PostgreSQL数据库 42.5 dropdb:删除PostgreSQL数据库 42.6 dropdb:删除PostgreSQL数据库 42.7 createuser:创建PostgreSQL用户 42.8 dropuser:删除PostgreSQL用户 42.9 pg_dump:备份数据库