Postgresql隔离级别测试

              从我们最开始了解数据库的时候,我们都知道事务是由一个或者多个SQL语句组成,并且这些语句要么全部执行成功、要门全部执行失败(这就是原子性 Atomic),并且事务将数据库从一个一致的状态转移到另一个一致的状态(这就是一致性:consistency),但是当数据库并发比较大的时候,多个session对于表记录进行并发操作的时候,Session之间的查询和操作是互不影响的,看上去各个事务像是一前一后串联发生(这就是隔离性:Isolation),事务在被提交后提供一个确定一致的结果,即使出现硬件故障等,它仍然保持一个一致的状态(这就是持久性:persistence),上述所说的就是事务的ACID属性,今天我们要登场的主角是Isolation。

              隔离性这个词从汉语上理解就是隔断级别,隔断级别,隔离的是所有客户端(数据库session)之间的影响,也就是决定了当其他事务同时运行时当前事务可以看到哪些数据,PG默认支持以下三种隔离级别(postgresql 9.6 事务隔离级别官方文档),

1、READ COMMITTED(读已提交)

A statement can only see rows committed before it began. This is the default.

某语句只能看到在它开始前提交的行,这是默认设置

2、REPEATABLE READ(可重复读)

All statements of the current transaction can only see rows committed before the first query or data-modification statement was executed in this transaction.

当前事务的所有语句只能查看在此事务中执行第一个查询或数据修改语句之前提交的行。

3、SERIALIZABLE(串行化读)

All statements of the current transaction can only see rows committed before the first query or data-modification statement was executed in this transaction. If a pattern of reads and writes among concurrent serializable transactions would create a situation which could not have occurred for any serial (one-at-a-time) execution of those transactions, one of them will be rolled back with a serialization_failure error.

当前事务的所有语句只能查看在此事务中执行第一个查询或数据修改语句之前提交的行。如果并发可序列化事务之间的读写模式将导致这些事务的任何串行(一次一次)执行都无法发生的情况,则其中一个事务将回滚并出现序列化失败错误。

            SQL标准定义了一个额外的级别,read uncommitted(读未提交)。在PostgreSQL中,读未提交被视为读已提交,读未提交的级别会产生脏读现象。

            查看postgres 的默认的隔离级别的设置

select a.name,a.setting,a.short_desc,a.vartype,a.enumvals,a.pending_restart from pg_settings a where a.name like '%isolation%';

PG默认隔离级别


postgresql.conf配置文件设置的数据库隔离级别

下面我们通过修改数据库的隔离级别进行各个事务隔离级别的测试,主要的测试目标是存在不同的隔离级别下的的情况下的并发session看到、修改数据的范围;



在进行测试之前我们需要在数据库中造一张员工表

create table employee_info(id serial,name text,address text,status text);

comment on column employee_info.name is '姓名';

comment on column employee_info.address is '住址';

comment on column employee_info.status is '在职状态';

INSERT INTO public.employee_info("name", address, status) VALUES('马克思', '南京江宁', '在职');

INSERT INTO public.employee_info("name", address, status) VALUES('恩格斯', '南京江宁', '在职');

INSERT INTO public.employee_info("name", address, status) VALUES('奥巴马', '南京浦口', '在职');

INSERT INTO public.employee_info("name", address, status) VALUES('布什', '南京玄武', '在职');

INSERT INTO public.employee_info("name", address, status) VALUES('普京', '南京玄武', '在职');



1、read uncommitted(读未提交)


上图的最左面的有向坐标代表时间轴,越往下时间越大,

time1 时刻:事务T1查询表A 中住在南京江宁区的在职员工人有哪些,查询出俩个在职员工;

time2 时刻:事务T2更新江宁区一个员工状态为离职;

time3 时刻:事务T1执行time1时刻的相同查询,此时只能查询出一个南京江宁的在职员工;但是这个时候的事务T2还没有提交,因此T1读取了脏数据,如果事务T2执行回滚操作的话,事务T1再执行查询的话,又能看到time1时刻查询到的俩条在职员工记录了。这就是脏读现象,只有read uncommitted隔离级别会产生脏读,在PG中,read uncommitted被视为read committed,也就是没有读未提交这种隔离级别,在此我们不做实际的演示操作。

2、read committed(读已提交)

以下是读已提交隔离级别事务执行时间图如下:


读提交测试图


time 1 时刻:psql开启一个新会话窗口,执行查询在职南京江宁员工查询 select * from employee_info where address='南京江宁' and status='在职',可以看到马克思和恩格斯都在职,并且都在南京江宁


time 1 事务T1执行查询在职的南京江宁员工

time 2时刻:在另一个psql窗口中执行更新马克思为离职,但是此时T2没有执行commit;

time 2 事务T2执行更新马克思为离职


time 3时刻:T1事务执行相同的查询,发现并没有查到T1未提交的更新数据,也就是没有产生脏读

time 3 事务T1在事务T2未提交后执行第二次相同查询

time 4时刻:事务T2执行提交事务操作,将数据持久化;

time 4 事务T2执行commit操作,提交事务

time 5时刻:事务T1执行相同的查询,发现在职的南京江宁员工只有恩格斯,事务T2的提交更新对事务T1已经可见;

time 5 事务T2在事务T1 commit后再执行相同的查询,只能查看到一条数据

time 6时刻:事务T2执行新增新员工,并且地址为南京江宁,没有执行提交操作;

time 6 T3新增一条数据未提交的时候

time 7时刻:事务T1执行相同的查询,没有发现事务T3未提交的新增数据,也就是未产生脏读

time 7 T1在T3未提交时候进行查询

time 8时刻:事务T3执行新增数据的提交操作;

time 8 T3提交事务

time 9时刻:事务T1执行相同的查询在职南京江宁员工发现了事务T3新提交的数据;

time 9  T1在T3提交后进行查询

总结:从上面的测试例子中我们可以看出,其他事务已经提交的数据变更将对其他绘画可见,未提交的变更对其他会话是不可见的,所以,脏读现象不会发生。但是相同的select语句在一个事务中的多次执行能够获得不同的结果,这意味着不可重复的读取。

3、Repeatable read(可重复读)

在进行可重复读测试之前,我们将上面的数据还原到初始化状态,

id|name|address|status|

1|马克思 |南京江宁  |在职    |

2|恩格斯 |南京江宁  |在职    |

3|奥巴马 |南京浦口  |在职    |

4|布什  |南京玄武  |在职    |

5|普京  |南京玄武  |在职    |

然后修改数据库的隔离级别,这里我们直接修改 PG配置文件postgresql.conf 数据库隔离参数 default_transaction_isolation = 'repeatable read',接着raload 最新的配置参数


2


修改隔离级别并查看是否生效

以下是可重复读隔离级别事务执行时间图:



time 1时刻:开启事务T1,执行查询select * from employee_info where address='南京江宁' and status='在职'; 


事务T1开启事务执行查询

time 2时刻:事务T2开启,执行更新操作,此时事务未提交;

事务T2开启,执行更新操作

time 3时刻:事务T1执行相同的查询,select * from employee_info where address='南京江宁' and status='在职',得到相同的结果,未产生脏读现象;

事务T1执行相同的查询

time 4时刻:事务T2执行commit 操作,提交事务;

事务T2执行commit

time 5时刻:事务T1执行相同的查询 select * from employee_info where address='南京江宁' and status='在职',得到相同的结果,这个结果及是不正确的,运维事务T2已经更新了马克思的在职状态,因此产生了幻读现象,读到的数据是真实数据的幻象

,但是结果集和T2未提交(T1开启事务)的时候是一样的,是可重复读的;

事务T1在T2执行commit后执行相同的查询  ,相同的结果集合

time 6时刻:事务T1更新恩格斯的在职状态更新为离职,更新成功,(如果在这之后执行commit操作的话,commit是成功的,笔者已经测试过),然后更新马克思的在职状态为离职,这个时候就报错:ERROR:  could not serialize access due to concurrent update,事务T1失败,回滚了;

事务1更新数据包括事务T2更新的数据

3、Serialized(串行化读)

同样修改数据库的事务隔离级别为serializable,还原数据为初始状态

以下是串行化读隔离级别事务执行时间图:


time 1时刻:事务T1开启,查询在职南京江宁员工


事务T1开启,查询在职南京江宁员工

time 2时刻:事务T2执行更新操作,将马克思的在职状态更新为离职

事务T2执行更新操作

time 3时刻:事务T1执行相同的查询,获得相同的结果

事务T1执行相同的查询,获得相同的结果

time 4时刻:事务T2执行commit操作,提交更新

事务T2执行commit

time 5时刻:事务T1执行相同的查询,获得相同的结果,

事务T1在T2commit后执行第三次相同的查询,获得相同的结果

time 6时刻:事务T1执行更新恩格斯的操作,更新失败(其实这一步执行更新表里面的任何一个记录都会失败),接下来执行commit也会自动执行回滚

T1在事务T2执行commit后执行update操作,事务回滚

从上面的三个测试例子中我们可以看出,

2、在读提交的隔离级别中,查询可以看到select语句开始执行前的所有session 提交的所有数据更改;

3、在可重复读和序列化读级别,查询只能看到事务开启时刻之前的所有 session提交的数据,保留的数据是事务开启时刻的快照版本,一直到commit这一时间点;

4、PG中序列化读取级别比可重复读级别更加严格,可重复读不能修改其他事务语句修改的记录,但是可以修改快照里面的其他记录,而序列化读只要有事务进行了修改,那么他做的所有的操作都会被回滚

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容