PostgreSQL 事务并发锁

文章目录

  • PostgreSQL 事务
    • 大家都知道的 ACID
    • 事务的基本使用
    • 保存点
  • PostgreSQL 并发
    • 并发问题
    • MVCC
  • PostgreSQL 锁机制
    • 表锁
    • 行锁
  • 总结

PostgreSQL 事务

大家都知道的 ACID

在日常操作中,对于一组相关操作,通常要求要么都成功,要么都失败。在关系型数据库中,称这一组操作为事务。为了保证整体事务的安全性,有ACID这一说:

  • 原子性A:事务是一个最小的执行单位,一次事务中的操作要么都成功,要么都失败。
  • 一致性C:在事务完成时,所有数据必须保持在一致的状态。(事务完成后吗,最终结果和预期结果是一致的)
  • 隔离性I:一次事务操作,要么是其他事务操作前的状态,要么是其他事务操作后的状态,不存在中间状态。
  • 持久性D:事务提交后,数据会落到本地磁盘,修改是永久性的。

PostgreSQL相比于其他数据库,有一个比较大的优化,DDL也可以包含在一个事务中。比如集群中的操作,一个事务可以保证多个节点都构建出一个表,才算成功。

事务的基本使用

PostgreSQL跟MySQL一样,是自动提交事务的。

可以基于关闭PostgreSQL的自动提交事务来进行操作。

image.png

但是上述方式比较麻烦,传统的方式。

也可以根据命令处理一个事务:

  • begin:开始事务
  • commit:提交事务
  • rollback:回滚事务
-- 开启事务
begin;
-- 操作
insert into test values (7,'bbb',12,5);
-- 提交事务 
commit;

保存点

在PostgreSQL中,保存点(savepoint)用于在事务中创建中间状态,点允许在事务过程中设置临时的“检查点”,以便在必要时回滚事务的一部分。

比如项目中有一个大事务操作超时,回滚成本太高。针对大事务,可以拆分成几个部分,每个部分完成后,构建一个保存点,如果后面操作超时了,回滚到保存点,继续重试。

-- savepoint操作
-- 开启事务
begin;
-- 插入一条数据
insert into test values (8,'铃铛',55,11);
-- 添加一个保存点
savepoint ok1;
-- 再插入数据,比如出了一场
insert into test values (9,'大唐官府',66,22);
-- 回滚到之前的提交点
rollback to savepoint ok1;
-- 就可以开始重试操作,重试成功,commit,失败可以rollback;
commit;

PostgreSQL 并发

并发问题

在不考虑隔离性的前提下,事务的并发可能会出现的问题:

  • 脏读:读到了其他事务未提交的数据。(必须避免这种情况)
  • 不可重复读:同一事务中,多次查询同一数据,结果不一致,因为其他事务修改造成的。(一些业务中这种不可重复读不是问题)
  • 幻读:同一事务中,在修改某个数据后,再次查询还是之前的数据,因为其他事务对数据进行了更新,这种现象为幻读。

针对这些并发问题,关系型数据库有一些事务的隔离级别,一般用4种。

  • READ UNCOMMITTED:读未提交
  • READ COMMITTED:读已提交,可以解决脏读(PGSQL默认隔离级别)
  • REPEATABLE READ:可重复读,可以解决脏读和不可重复读(MySQL默认是这个隔离级别,PGSQL也提供了,但是设置为可重复读,效果还是串行化)
  • SERIALIZABLE:串行化

PGSQL在老版本中,只有两个隔离级别,读已提交和串行化,在PGSQL中不存在脏读问题。

MVCC

PostgreSQL中,在事务的并发问题里,也是基于MVCC多版本并发控制去维护数据的一致性。详细内容见多版本并发控制MVCC

首先要清楚,为啥要有MVCC?

如果一个数据库,频繁的进行读写操作,为了保证安全,采用锁的机制。但是如果采用锁机制,如果一些事务在写数据,另外一个事务就无法读数据,会造成读写之间相互阻塞。 所以大多数的数据库都会采用一个机制 多版本并发控制 MVCC 来解决这个问题。

MVCC是一种并发控制的方法,它通过保存数据的多个版本来实现并发访问。在MVCC中,每个事务在开始时获取一个唯一的版本号,然后读取和修改数据时都会带上这个版本号。这样,每个事务只能看到自己的版本号小于或等于自己的数据版本,从而实现了并发访问。

PGSQL中,每张表都会自带两个字段

  • xmin:给当前事务分配的数据版本。如果有其他事务做了写操作,并且提交事务了,就给xmin分配新的版本。
  • xmax:当前事务没有存在新版本,xmax就是0。如果有其他事务做了写操作,未提交事务,将写操作的版本放到xmax中。提交事务后,xmax会分配到xmin中,然后xmax归0。

image.png

基于上图的操作查看效果

事务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;

PostgreSQL 锁机制

当然,PostgreSQL也支持表锁和行锁,来控制并发访问。PostgreSQL中主要有两种锁,一个表锁一个行锁。

表锁

表锁就是锁住整张表,也分为很多中模式,其中最核心的两个:

  • ACCESS SHARE:共享锁(读锁),读读操作不阻塞,但是不允许出现写操作并行
  • ACCESS EXCLUSIVE:互斥锁(写锁),无论什么操作进来,都阻塞。

具体的可以查看官网文档。

PostgreSQL中表锁的实现:

image.png

基于LOCK开启表锁,指定表的名字name,其次在MODE中指定锁的模式,NOWAIT可以指定是否在没有拿到锁时,一致等待。

-- 事务1
-- 基于互斥锁,锁住test表
-- 先开启事务
begin;
-- 基于默认的ACCESS EXCLUSIVE锁住test表
lock test in ACCESS SHARE mode;
-- 操作
select * from test;
-- 提交事务,锁释放
commit;

当事务1开启锁住当前表之后,如果使用默认的ACCESS EXCLUSIVE,其他连接操作表时,会直接阻塞住。

如果事务1是基于ACCESS SHARE共享锁时,其他事务是可以查询当前表的。

行锁

PostgreSQL的行锁和MySQL的基本是一模一样的,基于select for update就可以指定行锁。

MySQL中有一个概念,for update时,如果select的查询没有命中索引,可能会锁表。

PostgerSQL有个特点,for update时,如果select的查询没有命中索引,不一定会锁表,依然会实现行锁。

-- 先开启事务
begin;
-- 基于for update 锁住id为3的数据
select * from test where id = 3 for update;
update test set name = 'v1' where id = 3;
-- 提交事务,锁释放
commit;

其他的事务要锁住当前行,会阻塞住。

总结

事务、MVCC和锁是三个相互关联的概念,它们共同保证了数据库的一致性和并发性。

  • 事务和MVCC是互相配合的,事务通过MVCC来实现并发控制,保证数据的一致性。
  • 锁是事务实现并发控制的一种手段,通过加锁来保证数据的一致性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/109575.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ESIM实战文本匹配

引言 今天我们来实现ESIM文本匹配,这是一个典型的交互型文本匹配方式,也是近期第一个测试集准确率超过80%的模型。 我们来看下是如何实现的。 模型架构 我们主要实现左边的ESIM网络。 从下往上看,分别是 输入编码层(Input Ecoding) 对前…

智慧工地:实现作业区域安全管控

智慧工地是围绕工程现场人、机、料、法、环及施工过程中质量、安全、进度、成本等各项数据满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效。 建设工程安全文明施工与质量提升,全方位的监测施工人员、各类器械设备、消防安全隐患,并提前对风险进行预警…

Linux vim的常见基本操作

目录 vim是一款多模式的编辑器 命令模式下: 用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格 gg:定位到代码第一行 nshiftg 定位到任意一行/最后一行 「 $ 」:移动到光标所在行的结尾 「 ^ 」&…

flutter run长时间卡在Running Gradle task “assembleDebug“问题解决

1.下载离线gradle, 在android>>gradle>>wrapper 中找到gradle-wrappper.properties 可以看到要下载的gradle的版本 下载官方链接,更改url的版本号就好 Gradle | Thank you for downloading Gradle! 在android>>gradle>>wrapper 中找到gradle-wra…

UG\NX二次开发 二维向量相加

文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C++-CSDN博客 简介: UG\NX二次开发 二维向量相加 效果: 代码: #include "me.hpp"void doIt() {const double vec1[2] = { 1.0,2.0 };const double vec2[2] = { 2.0,2.…

EasyExcel入门(最简单的读)

官网:EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel (alibaba.com) 因为暂时项目没有用到,所以不急,知道了这个技术。就想着学着用一下! 最简单的读 先看官方文档给的用法和解释!!&#xff01…

30天入门Python(基础篇)——第2天:Python安装(保姆级)与IDE的认识与选择+详细安装教程

文章目录 专栏导读上一节课回顾1、Python解释器的安装查看各个版本的Python解释器①、ok,双击安装②、这里我们选择【自定义】安装, 下面的【将Python添加在环境变量】大家一定要打个勾③、点击【Next】进行下一步④、这里不建议安装在C盘, 点击【Browse】我在F盘创…

【DevOps系列】Docker数据卷(volume)详解

【DevOps系列】Docker数据卷(volume)详解 文章目录 【DevOps系列】Docker数据卷(volume)详解一、概述二、数据卷三、为什么使用数据卷volume数据卷的作用:数据卷的特点: 四、数据卷volume基本操作4.1 创建数…

小程序中如何查看指定会员的付款记录

在小程序中,我们可以通过一些简单的步骤来查看指定会员的付款记录。下面是具体的操作流程: 1. 找到指定的会员卡。在管理员后台->会员管理处,找到需要查看付款记录的会员卡。也支持对会员卡按卡号、手机号和等级进行搜索。 2. 查看会员卡…

测试平台前端部署

这里写目录标题 一、前端代码打包1、打包命令2、打包完成后,将dist文件夹拷贝到nginx文件夹中3、重新编写default.conf4、将之前启动的容器进行停止并且删除,再重新创建容器5、制作Dockerfile二、编写Dockerfile一、前端代码打包 1、打包命令 npm run build2、打包完成后,…

【C语言】指针和数组笔试题解析

指针是C语言的灵魂,他的玩法多种多样,这篇文章带来指针的笔试题详解,可以帮助我们更好的理解与巩固指针的知识 目录 预备知识:题目: 题目比较多,但切记戒骄戒躁,保持空杯心态,相信看…

高级深入--day23

处理给规范的文字 处理的大多数文字最好都是比较干净、格式规范的。格式规范的文字通常可以满足一些需求,通常格式规范的文字具有以下特点: 使用一个标准字体(不包含手写体、草书,或者十分“花哨的”字体)即使被复印或拍照,字体还是很清晰,…