Transaction事务
** Transaction & ACID **
在对数据库的常规操作过程中,我们一般希望一组操作要么全部成功,要么全部失败,不希望出现一部分成功,一部分失败的情况(可能导致数据的混乱,较难纠正); 在RDBMS中,这种一组操作叫做Transaction,Transaction拥有ACID的特性,详情如下:
1、原子性(atomicity): 事务必须以一个整体单元的形式进行,这一组操作(SELECT、UPDATE、DELETE、INSERT等),要么全部进行完毕,要么全部不执行,如果异常中断就需要进行全部的回退操作;
2、一致性(consistency): 事务在结束时,数据必须全部处于相同版本(保持一致的状态,并非所有数据都相同,而是版本相同,例如2018-04-03 12:00:03完成了一组Transaction,那么所有被操作的数据结束时都应该是操作完毕时的数据,而不是部分数据中间状态或者以前的状态)
3、隔离性(isolation): 事务查看数据时的状态,数据并不会处于某事务的中间状态,要么为另一个事务修改它之前的状态,要么是另一个事务修改它之后的状态;
4、持久性(durability): 事务完成之后,应该永久存储数据,不会因为数据库宕机而消失或者改变;
在PostgrelSQL中,通过MVCC来维护数据的一致性的,相比于锁定模型,MVCC的优点是Read Lock和Write Lock之间之前是不会阻塞的,在PG中提供了表级别和行级别锁定语句;
** 事务隔离级别 **
Transaction Isolation有以下4个级别:
1、READ UNCOMMITTED
2、READ COMMITTED
3、REPEATABLE READ
4、SERIALIZABLE
要了解这4个隔离级别,我们得先了解三种不一致的情况:
1、脏读: 一个事务读取了另一个未提交事务写入的数据,如果发生脏读,数据一致性控制上会出现很大问题;
2、不可重复读: 你开始了一次银行卡余额的查询, 此时余额是10,000元,这时候,你的女朋友购置了800元的日常用品以及一支YSL(直男只知道YSL了)的口红,你再查询的时候(本次操作还未结束,只是在这组操作再查询一次而已),余额变成了9,200元, 这就是不可重复读;
3、幻影读(幻读):一个事务开始后,需要更新一批数据,更新后重新查询数据发现仍然存在一些未被修改的数据(因为是新插入);
例如:
--Session 1:
mydb# SELECT id,name,loc FROM t_name
WHERE name = 'NiuJinlin';
id | name | LOC
---------------------------
1 | NiuJinlin | BeiJing
2 | NiuJinlin | ShangHai
3 | NiuJinlin | Shenzhen
(3 rows)
--Transaction 1(Session 1):
mydb# UPDATE t_name SET loc = 'UNKNOW'
WHERE name = 'NiuJinlin';
--Transaction 2(Session 2):
mydb# INSERT INTO t_name VALUES (4,'NiuJinlin','England');
mydb# COMMIT;
--Session 1:
mydb# SELECT ID,NAME,LOC FROM T_NAME
WHERE NAME = 'NiuJinlin';
id | name | LOC
---------------------------
1 | NiuJinlin | UNKNOW
2 | NiuJinlin | UNKNOW
3 | NiuJinlin | UNKNOW
4 | NiuJinlin | England
(3 rows)
隔离级别 | 脏读 | 不可重复读 | 幻读 |
READ UNCOMMITTED | ✔️ | ✔️ | ✔️ |
READ COMMITTED | ❌ | ✔️ | ✔️ |
REPEATABLE READ | ❌ | ❌ | ✔️ |
SERIALIZABLE | ❌ | ❌ | ❌ |
在PostgreSQL 9.1之前的版本中,仅仅支持READ COMMITTED和SERIALIZABLE,之后的版本可以支持REPEATABLE READ,但是READ UNCOMMITTED事实上仍然不可以支持脏读;