文章目录
PostgreSQL的并发问题
一、事务的隔离级别
在不考虑隔离性的前提下,事务的并发可能会出现的问题:
-
脏读:读到了其他事务未提交的数据。(必须避免这种情况)
-
不可重复读:同一事务中,多次查询同一数据,结果不一致,因为其他事务修改造成的。(一些业务中这种不可重复读不是问题)
-
幻读:同一事务中,多次查询同一数据,因为其他事务对数据进行了增删吗,导致出现了一些问题。(一些业务中这种幻读不是问题)
针对这些并发问题,关系型数据库有一些事务的隔离级别,一般用4种。
-
READ UNCOMMITTED:读未提交(啥用没用,并且PGSQL没有,提供了只是为了完整性)
-
READ COMMITTED:读已提交,可以解决脏读(PGSQL默认隔离级别)
-
REPEATABLE READ:可重复读,可以解决脏读和不可重复读(MySQL默认是这个隔离级别,PGSQL也提供了,但是设置为可重复读,效果还是串行化)
-
SERIALIZABLE:串行化,啥都能解决(锁,效率慢)
PGSQL在老版本中,只有两个隔离级别,读已提交和串行化。在PGSQL中就不存在脏读问题。
二、MVCC
首先要清楚,为啥要有MVCC。
如果一个数据库,频繁的进行读写操作,为了保证安全,采用锁的机制。但是如果采用锁机制,如果一些事务在写数据,另外一个事务就无法读数据。会造成读写之间相互阻塞。 大多数的数据库都会采用一个机制 多版本并发控制 MVCC 来解决这个问题。
比如你要查询一行数据,但是这行数据正在被修改,事务还没提交,如果此时对这行数据加锁,会导致其他的读操作阻塞,需要等待。如果采用PostgreSQL,他的内部会针对这一行数据保存多个版本,如果数据正在被写入,包就保存之前的数据版本。让读操作去查询之前的版本,不需要阻塞。等写操作的事务提交了,读操作才能查看到最新的数据。 这几个及时可以确保读写操作没有冲突 ,这个就是MVCC的主要特点。
写写操作,和MVCC没关系,那个就是加锁的方式!
Ps:这里的MVCC是基于 读已提交 去聊的,如果是串行化,那就读不到了。
在操作之前,先了解一下PGSQL中,每张表都会自带两个字段
-
xmin:给当前事务分配的数据版本。如果有其他事务做了写操作,并且提交事务了,就给xmin分配新的版本。
-
xmax:当前事务没有存在新版本,xmax就是0。如果有其他事务做了写操作,未提交事务,将写操作的版本放到xmax中。提交事务后,xmax会分配到xmin中,然后xmax归0。
基于上图的操作查看一波效果
事务A
-- 左,事务A
--1、开启事务
begin;
--2、查询某一行数据, xmin = 630,xmax = 0
select xmin,xmax,* from test where id = 8;
--3、每次开启事务后,会分配一个事务ID 事务id=631
select txid_current();
--7、修改id为8的数据,然后在本事务中查询 xmin = 631, xmax = 0
update test set name = '铃铛' where id = 8;
select xmin,xmax,* from test where id = 8;
--9、提交事务
commit;
事务B
-- 右,事务B
--4、开启事务
begin;
--5、查询某一行数据, xmin = 630,xmax = 0
select xmin,xmax,* from test where id = 8;
--6、每次开启事务后,会分配一个事务ID 事务id=632
select txid_current();
--8、事务A修改完,事务B再查询 xmin = 630 xmax = 631
select xmin,xmax,* from test where id = 8;
--10、事务A提交后,事务B再查询 xmin = 631 xmax = 0
select xmin,xmax,* from test where id = 8;
-
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
-
📢本文由 Lansonli 原创,首发于 CSDN博客🙉
-
📢停下休息的时候不要忘了别人还在奔跑,希望大家抓紧时间学习,全力奔赴更美好的生活✨