隔离级别是有一套理论的,在每种数据库中,实现的方式不同,实现的结果也不同,最近会有几期的文字对不同的数据库的隔离级别探探究竟。
传统数据库中的隔离级别是配合MVCC 多版本控制来完成读取不会阻塞写,在任意时刻,每个事务都能看到读取当时数据的快照,避免数据发生变化后,事务在整个流程中看到的数据是不同的.
实际上每种数据库的在MVCC的中如何完成都有自己的形成的原理, 今天通过POSTGRESQL 来验证POSTGRESQL 中的序列 Serializable 在数据库操作中是什么样子.
我们先调整POSTGRESQL 的数据库到序列化的模式.
1 通过POSTGRESQL 中的参数调整,然后重新RELOAD系统
2 通过SESSION 的方式控制当前的访问的进程为序列化
下面我们采用第一种方式,把default_transaction_isolation 制为 'serializable'
我们建立一个数据库test
然后建立一个表
CREATE TABLE employee
(id INTEGER
, name VARCHAR(50)
);
INSERT INTO employee (id,name)
VALUES
(1,'anvesh'),(2,'neevan')
,(3,'roy'),(4,'martin');
然后我们打开三个进程,A B C ,分别在每个进程下执行如下命令
SESSIONA
BEGIN TRANSACTION ISOLATION LEVELSERIALIZABLE;
UPDATE employee SET Name ='varlin' WHERE id=4;
SELECT * FROM employee;
SESSION B
UPDATE employee SET name ='Loother' WHERE id=3;
SESSION C
INSERT INTO Employee (id,name) VALUES (5,'mahi');
SELECT * FROM employee;
SESSION A
SELECT * FROM employee;
结果和序列化的定义预期是一致的
SESSION A 只能看到自己在事务定义时刻的数据,以及对那一个时刻的数据的改变,SESSION B SESSION C 也可以到底自己执行命令时刻以及改变数据时刻后的数据的变化.
SESSION A
SESSION B
SESSION C
但注意此时的SESSION A SESSION B SESSION C 之间并没有冲突,因为互相并未干涉同一行数据.
此时我们将SESSION B 的操作在SESSION A 中操作. 我们得到一个错误
2021-02-09 06:22:25.477 EST [33403] ERROR: could not serialize access due to concurrent update
2021-02-09 06:22:25.477 EST [33403] STATEMENT: UPDATE employee SET name ='Loother' WHERE id=3;
ERROR: could not serialize access due to concurrent update
通过上图我们捋一捋, 实际上如果每个进程炒作的数据之间没有关系,则序列化的隔离级别不会影响每个进程的操作, 而如果进程之间操作的数据是同一行数据,则序列化的问题就出现了.
SESSION A 中的 ID = 3 的一行的数据变化必须按照时间的序列的要求,需要在退出事务后,才能进行,也就是说以事务为单位,每行数据具有时间顺序操作的需要.
我们通过下面的例子,在此验证上面的假设
我们分别在SESSION A B C ,三个进程, 依次的执行
update employee set name = 'siome' where id = 1; A
update employee set name = 'siome' where id = 1; B
update employee set name = 'siome' where id = 1; C
SESSION A 我们可以清晰的看到 SESSION B SESSION C 在执行中报错
SESSION B SESSION C 即使在SESSION A COMMIT 后, COMMIT 也只能进行回滚.
SESSION B
通过上的例子可以验证在序列化中,如果一个事务占有了某个一个行,则其他进程的事务是无法对这个行进行任何DML 的操作的.