PostgreSQL技术内幕9:PostgreSQL事务原理解析

news2024/9/17 0:56:08

文章目录

    • 0.简介
    • 1.PG事务整体介绍
      • 1.1 事务类型介绍
    • 1.2 事务模块介绍
    • 2. 代码分析

0.简介

有了上一篇数据库事务并发控制协议的介绍,对于数据库事务和并发控制有了基本的认识,本文将介绍PG事务模块,主要介绍PG支持的事务类型(普通事务,子事务,多事务,2pc事务),事务模块涉及的的子模块整体介绍(日志模块,MVCC管理,事务锁管理)和事务模块代码脉络解读。日志模块、MVCC管理和事务锁管理详细内容将在后续文章中介绍。

1.PG事务整体介绍

1.1 事务类型介绍

从事务类型上来区分,PG包含普通的事务,子事务,多事务,2PC事务。
普通事务:
普通事务是数据库操作的基本单位,用于确保数据的完整性和一致性。在PostgreSQL中,普通事务可以通过BEGIN命令开始,通过COMMIT命令提交,或通过ROLLBACK命令回滚。在默认情况下,如果客户端没有显式地开始一个事务,PostgreSQL会在执行每个DML(数据操纵语言)语句时自动提交事务,即每条DML语句都被视为一个单独的事务。但用户可以通过设置AUTOCOMMIT为off或使用BEGIN命令来显式地控制事务的开始和结束。
用PG客户端直接连接PG服务器会默认开始事务的自动提交,就是把每一句SQL当成一个事务自动提交。可以使用set autocommit off关闭自动提交,或者使用begin开启一个事务块(一组被BEGIN和COMMIT包围的语句也被称为一个事务块。),下面用一个例子来具体看一看:

postgres=# \echo :AUTOCOMMIT
on
postgres=# create table t3(a int);
CREATE TABLE
postgres=# \set AUTOCOMMIT off
postgres=# \echo :AUTOCOMMIT
off
postgres=# insert into t3 values(1);
INSERT 0 1
postgres=# rollback;
ROLLBACK
postgres=# select * from t3;
 a
---
(0 rows)

postgres=# insert into t3 values(2);
INSERT 0 1
postgres=# commit;
COMMIT
postgres=# select * from t3;
 a
---
 2
(1 row)
    

可以使用如下语句查看数据信息,其中记录所有事务的状态:

select lp,t_xmin,t_xmax,t_ctid,t_infomask,t_data from heap_page_items(get_raw_page('t3',0));

事务信息物理存储在PGDATA目录下的pg_xact文件夹,这里的文件记录了事务的提交状态。2bit记录一个事务的状态,一个byte可以记录4个事务状态,这里每一个文件的size在内核中规定为32BLCKSZ,比如0000文件所记录的事务ID范围是(1~32BLCKSZ*4)。因此想要获取一个事务的提交状态,到pg_xact目录下取就可以了。
子事务
子事务是在一个普通事务内部创建的更小的事务单位。它们允许部分事务的回滚,而不需要回滚整个事务。在PostgreSQL中,子事务通过SAVEPOINT命令来创建保存点,并通过ROLLBACK TO SAVEPOINT命令回滚到指定的保存点。虽然子事务不能直接提交,但它们会随着父事务的提交而提交。子事务在处理大量数据或复杂逻辑时非常有用,因为它允许在出现问题时仅回滚部分操作,而不是整个事务。
子事务是调用savepoint或者exception而出现的,多个子事务共同组成一个完整的事务。

postgres=# begin;
BEGIN
postgres=# insert into t3 values(6);
INSERT 0 1
postgres=# savepoint s1;
SAVEPOINT
postgres=# insert into t3 values(7);
INSERT 0 1
postgres=# savepoint s2;
SAVEPOINT
postgres=# select txid_current();
 txid_current
--------------
          585
(1 row)

postgres=# commit;
COMMIT
postgres=# select ctid,xmin,* from t3;
 ctid  | xmin | a
-------+------+---
 (0,2) |  581 | 2
 (0,4) |  585 | 6
 (0,5) |  586 | 7
(3 rows)

可以看到,数据有着不同的事务id,585为父事务,586为子事务,子事务可以当成是一种特殊的普通事务,也有提及状态吗,也会再pg_xact中记录,所有的父事务和子事务,最用都要标记为commit或者abort,为了保证整个父事务和子事务的原则性,提交机制如下:
1)子事务先标记为子事务提交
(TRANSACTION_STATUS_SUB_COMMITTED)
2)标记父事务状态为已提交
(TRANSACTION_STATUS_COMMITTED)
3)标记子事务状态为已提交
(TRANSACTION_STATUS_COMMITTED)
如果子事务在pg_xact目录记录状态为已提交,那么子事务就是提交状态;如果子事务状态为子事务提交,子事务状态的判断需要根据父事务的状态来判断;如果是其他情况,就是未提交。子事务和父事务的对应关系记录在pg_subtrans目录下。
在文件中,使用4byte记录一个子事务父事务id,每个文件size在内核中规定为32blcksz,比如0000文件记录的事务id范围为(1~32blcksz/4)
多事务
多事务通常与行级锁相关,出现在多个会话对同一行记录添加行级锁时。在这种情况下,每个会话都可以视为一个独立的事务,但它们的操作可能会相互影响,因为数据库需要管理这些事务对共享资源的访问。多事务的处理是数据库并发控制的一部分,PostgreSQL通过其MVCC(多版本并发控制)机制来管理这种并发情况,确保数据的一致性和隔离性。
多事务记录在pg_multixact目录下,里面记录了多事务和其对应事务列表的关联关系,事务列表中事务属性决定了多事务的提交状态。
2PC事务
2PC事务是一种分布式事务处理协议,用于确保在多个数据库或事务性资源之间执行的事务的原子性。2PC事务分为两个阶段:准备阶段和提交阶段。在准备阶段,所有参与者(如数据库)都会准备提交事务,但在实际提交之前,它们会等待协调者的进一步指示。如果所有参与者都准备好了,协调者会发出提交命令,所有参与者将同时提交事务。如果任何参与者在准备阶段失败,协调者将发出回滚命令,所有参与者将回滚事务。
PG中通过prepare和commit prepared xxx语句来执行,比如:prepare transaction '2pc_trans’是第一阶段提交,commit prepared ‘2pc_trans’;是第二阶段提交。2PC事务可以认为是一种特殊的普通事务,其提交状态判断和正常事务一样,但是2pc事务可以不依赖Session连接,数据库关闭也不会影响2PC事务状态,其保存的事务数据文件在pg_twophase中。

1.2 事务模块介绍

从模块架构来看,分为日志模块,MVCC管理模块和锁管理模块

在这里插入图片描述

2. 代码分析

代码整体结构可以参考src/backend/access/transam/README,以下是部分内容和翻译:

PostgreSQL's transaction system is a three-layer system.  The bottom layer
implements low-level transactions and subtransactions, on top of which rests
the mainloop's control code, which in turn implements user-visible
transactions and savepoints.
PG事务分为3,底层实现了低层次的事务和子事务,在其顶上驻留主循环控制代码,
而主循环实现了用户可见性事务和保存点.

The middle layer of code is called by postgres.c before and after the
processing of each query, or after detecting an error:
代码的中间层由 postgres.c 调用在处理每个查询流程,或者在检测到错误后:
    StartTransactionCommand
    CommitTransactionCommand
    AbortCurrentTransaction

Meanwhile, the user can alter the system's state by issuing the SQL commands
BEGIN, COMMIT, ROLLBACK, SAVEPOINT, ROLLBACK TO or RELEASE.  The traffic cop
redirects these calls to the toplevel routines
同时,用户可以通过发出 SQL 命令来更改系统的状态BEGIN、COMMIT、ROLLBACK、SAVEPOINT、
ROLLBACK TO 或 RELEASE。 将这些调用重定向到顶级例程
    BeginTransactionBlock
    EndTransactionBlock
    UserAbortTransactionBlock
    DefineSavepoint
    RollbackToSavepoint
    ReleaseSavepoint

respectively.  Depending on the current state of the system, these functions
call low level functions to activate the real transaction system:
分别。 根据系统的当前状态,分别调用这些功能 low level 函数来激活 
Real Transaction 系统:
    StartTransaction
    CommitTransaction
    AbortTransaction
    CleanupTransaction
    StartSubTransaction
    CommitSubTransaction
    AbortSubTransaction
    CleanupSubTransaction

For example, consider the following sequence of user commands:

1)    BEGIN
2)    SELECT * FROM foo
3)    INSERT INTO foo VALUES (...)
4)    COMMIT

In the main processing loop, this results in the following function call
sequence:

     /  StartTransactionCommand;
    /       StartTransaction;
1) <    ProcessUtility;                 << BEGIN
    \       BeginTransactionBlock;
     \  CommitTransactionCommand;

    /   StartTransactionCommand;
2) /    PortalRunSelect;                << SELECT ...
   \    CommitTransactionCommand;
    \       CommandCounterIncrement;

    /   StartTransactionCommand;
3) /    ProcessQuery;                   << INSERT ...
   \    CommitTransactionCommand;
    \       CommandCounterIncrement;

     /  StartTransactionCommand;
    /   ProcessUtility;                 << COMMIT
4) <        EndTransactionBlock;
    \   CommitTransactionCommand;
     \      CommitTransaction;


事务状态结构

typedef enum TransState
{
  TRANS_DEFAULT,        /* idle */
  TRANS_START,        /* transaction starting */
  TRANS_INPROGRESS,      /* inside a valid transaction */
  TRANS_COMMIT,        /* commit in progress */
  TRANS_ABORT,        /* abort in progress */
  TRANS_PREPARE,        /* prepare in progress */
} TransState;

/*
 *  transaction block states - transaction state of client queries
 *
 * Note: the subtransaction states are used only for non-topmost
 * transactions; the others appear only in the topmost transaction.
 */
typedef enum TBlockState
{
  /* not-in-transaction-block states */
  TBLOCK_DEFAULT,        /* idle */
  TBLOCK_STARTED,        /* running single-query transaction */

  /* transaction block states */
  TBLOCK_BEGIN,        /* starting transaction block */
  TBLOCK_INPROGRESS,      /* live transaction */
  TBLOCK_IMPLICIT_INPROGRESS, /* live transaction after implicit BEGIN */
  TBLOCK_PARALLEL_INPROGRESS, /* live transaction inside parallel worker */
  TBLOCK_END,          /* COMMIT received */
  TBLOCK_ABORT,        /* failed xact, awaiting ROLLBACK */
  TBLOCK_ABORT_END,      /* failed xact, ROLLBACK received */
  TBLOCK_ABORT_PENDING,    /* live xact, ROLLBACK received */
  TBLOCK_PREPARE,        /* live xact, PREPARE received */

  /* subtransaction states */
  TBLOCK_SUBBEGIN,      /* starting a subtransaction */
  TBLOCK_SUBINPROGRESS,    /* live subtransaction */
  TBLOCK_SUBRELEASE,      /* RELEASE received */
  TBLOCK_SUBCOMMIT,      /* COMMIT received while TBLOCK_SUBINPROGRESS */
  TBLOCK_SUBABORT,      /* failed subxact, awaiting ROLLBACK */
  TBLOCK_SUBABORT_END,    /* failed subxact, ROLLBACK received */
  TBLOCK_SUBABORT_PENDING,  /* live subxact, ROLLBACK received */
  TBLOCK_SUBRESTART,      /* live subxact, ROLLBACK TO received */
  TBLOCK_SUBABORT_RESTART,  /* failed subxact, ROLLBACK TO received */
} TBlockState;

/*
 *  transaction state structure
 */
typedef struct TransactionStateData
{
  FullTransactionId fullTransactionId;  /* my FullTransactionId */
  SubTransactionId subTransactionId;  /* my subxact ID */
  char     *name;      /* savepoint name, if any */
  int      savepointLevel; /* savepoint level */
  TransState  state;      /* low-level state */
  TBlockState blockState;    /* high-level state */
  int      nestingLevel;  /* transaction nesting depth */
  int      gucNestLevel;  /* GUC context nesting depth */
  MemoryContext curTransactionContext;  /* my xact-lifetime context */
  ResourceOwner curTransactionOwner;  /* my query resources */
  TransactionId *childXids;  /* subcommitted child XIDs, in XID order */
  int      nChildXids;    /* # of subcommitted child XIDs */
  int      maxChildXids;  /* allocated size of childXids[] */
  Oid      prevUser;    /* previous CurrentUserId setting */
  int      prevSecContext; /* previous SecurityRestrictionContext */
  bool    prevXactReadOnly;  /* entry-time xact r/o state */
  bool    startedInRecovery;  /* did we start in recovery? */
  bool    didLogXid;    /* has xid been included in WAL record? */
  int      parallelModeLevel;  /* Enter/ExitParallelMode counter */
  bool    chain;      /* start a new block after this one */
  bool    topXidLogged;  /* for a subxact: is top-level XID logged? */
  struct TransactionStateData *parent;  /* back link to parent */
} TransactionStateData;

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git为不同的项目设置不同的提交作者

方法1&#xff1a;找到项目的.git文件夹打开 打开config在下面添加自己作者信息 [user]name 作者名email 邮箱方法2&#xff1a;直接在.git文件夹设置作者名&#xff08;不使用–global参数&#xff09; git config user.name "xxxxx"如果想要修改之前提交的…

银行结算业务

1.1 银行本票 银行本票是由银行签发的,承诺自己在见票时无条件支付票款给收款人或持票人的业务。银行本票按票面划分为定额本票和不定额本票,按币种划分为人民币银行本票和外币银行本票。人民币银行本票仅在同一交换区域内使用,资金清算利用当地人民银行组织的资金清算形式…

vllm源码解析(五):LLM模型推理

八 模型推理细节探索 8.1 回顾下step的流程 def step(self) -> List[Union[RequestOutput, EmbeddingRequestOutput]]:# 多GPU并行推理时走AsyncLLMEngine分支。如果进入当前LLMEngine,性能会下降&#xff0c;这里会抛出异常。if self.parallel_config.pipeline_parallel_s…

基于机器学习的电商优惠券核销预测

1. 项目简介 随着移动互联网的快速发展&#xff0c;O2O&#xff08;Online to Offline&#xff09;模式已成为电商领域的一大亮点。优惠券作为一种有效的营销工具&#xff0c;被广泛应用于吸引新客户和激活老用户。然而&#xff0c;传统的随机投放方式往往效率低下&#xff0c;…

JavaWeb【day11】--(SpringBootWeb案例)

SpringBootWeb案例 前面我们已经实现了员工信息的条件分页查询以及删除操作。 关于员工管理的功能&#xff0c;还有两个需要实现&#xff1a; 新增员工 修改员工 首先我们先完成"新增员工"的功能开发&#xff0c;再完成"修改员工"的功能开发。而在&quo…

万能视频下载器-下载所有网站上的任何视频

万能视频下载器-下载所有网站上的任何视频 在Edge浏览器中发现了一款令人惊叹的视频下载扩展插件&#xff0c;简直就是视觉盛宴的利器&#xff01;只需轻点几下&#xff0c;在拓展商店中轻松查找并安装&#xff0c;你便能随时随地随心所欲地把心仪的视频收入囊中。无论是教学资…

matlab仿真 OFDM系统仿真

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第九章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; clear all N8;%子载波数 f1:N;%各个子载波频率 xrandi([0 3],1,N);%子载波上的数据 x1qammod(x,4);%4-QAM调制 t0:0.001:1-0.…

学习周报-2024.9.3

目录 摘要 Abstract 文献阅读&#xff1a;一种改善河流水质预测的耦合模型以解决非平稳性和数据限制 一、现有问题 二、提出方法 三、相关知识 1、基于小波分析的LSTM&#xff08;WA-LSTM&#xff09; 2、迁移学习TL改进WA-LSTM 四、WA-LSTM-TL模型 五、研究实验 1、…

手写NACOS的服务的注册与发现|心跳机制|轮询调用服务功能

背景 手写NACOS的服务的部分核心功能&#xff0c;提高自身的编码能力 本篇文章设计的是单体NACOS后端服务&#xff0c;提供SDK给多个NACOS客户端使用 本文编写了注册与发现|心跳机制|轮询调用服务功能&#xff0c;可当做入门级阅读 nacos-service 项目结构 代码内容 pom配置…

Detect It Easy

Detect It Easy&#xff08;简称 DIE&#xff09;项目的网址为 https://github.com/horsicq/Detect-It-Easy 下载完安装包后&#xff0c;直接双击die.exe即可进入到操作界面 工具介绍&#xff1a; 它可以用来检测程序架构和文件类型。如图所示。其中&#xff0c;「模式」说明程…

UE5 贝塞尔曲线导弹

首先创建导弹Actor蓝图 代码逻辑&#xff0c;这其中创建的所有变量都不用添加值&#xff0c;这些逻辑要画图来解释&#xff0c;比较麻烦&#xff0c;大家自行理解一下 接下来进入人物蓝图编写代码逻辑&#xff0c;我这里是在两个不同的位置发射两枚导弹 宏中的代码&#xff0c;…

时序预测|基于粒子群优化支持向量机的时间序列预测Matlab程序PSO-SVM 单变量和多变量 含基础模型

时序预测|基于粒子群优化支持向量机的时间序列预测Matlab程序PSO-SVM 单变量和多变量 含基础模型 文章目录 一、基本原理1. 问题定义2. 数据准备3. SVM 模型构建4. 粒子群优化&#xff08;PSO&#xff09;5. 优化与模型训练6. 模型评估与预测7. 流程总结8. MATLAB 实现概述 二、…

Python QT实现A-star寻路算法

目录 1、界面使用方法 2、注意事项 3、补充说明 用Qt5搭建一个图形化测试寻路算法的测试环境。 1、界面使用方法 设定起点&#xff1a; 鼠标左键双击&#xff0c;设定红色的起点。左键双击设定起点&#xff0c;用红色标记。 设定终点&#xff1a; 鼠标右键双击&#xf…

轻松上手,高效产出:音频剪辑工具年度精选

不知道你有没有拍vlog记录生活的习惯&#xff0c;有时候视频里穿插进自己的声音能让视频更加丰富贴上自己的标签。这次我们一起探讨当下有哪些好用的在线音频剪辑工具。 1.FOXIT音频剪辑 链接直达>>https://www.foxitsoftware.cn/audio-clip/ 这个工具是一款专业的音…

GNU的伪操作 (25)

这里主要是 对 GNU的 各个伪操作进行 详细的解释。 先来看着几个 伪操作。 .byte, .short, .long, .quad , .float , 这个是关于 字节的。 .string .ascii 是关于字符串的。 这个字符串编译器是可以自动在末尾补0 的。 举例&#xff1a; val: .word 0x11223344 mov r…

计算机组成原理(SRAM电路图示)

1.该电路由6个MOS管&#xff08;T1-T6&#xff09;组成 2.T1-T4是一个由MOS管组成的触发器基本电路&#xff1b; T5&#xff0c;T6像开关&#xff0c;受行地址选择信号控制&#xff1b; T7,T8受列地址选择控制&#xff0c;分别与位线A&#xff0c;和相连 3.假设触发器…

FinOps原则:云计算成本管理的关键

导语&#xff1a; FinOps 原则为我们提供了北极星&#xff08;North Star&#xff09;&#xff0c;在我们实践云财务管理时指导我们的活动。这些原则由 FinOps 基金会成员制定&#xff0c;并通过经验磨练出来。 北极星&#xff08;North Star&#xff09;的含义&#xff1a; …

不用管理员权限直接修改windows中hosts值的方法

本文只适用于少数经常修改hosts文件的程序员帅哥和美女们。 背景&#xff1a;直接修改hosts文件的不足 修改C:\Windows\System32\drivers\etc\hosts时&#xff0c;必须要管理员权限。 经常修改&#xff0c;会觉得有一丝丝麻烦。 方法1 &#xff08;安全性低&#xff0c;不…

ThinkPHP5 5-rce远程代码执行漏洞复现

启动容器 docker-compose up -d 查看端口 docker ps 端口为:8080,访问网站&#xff0c;搭建成功 漏洞复现 &#xff08;1&#xff09;输出关于 PHP 配置的信息 &#xff08;2&#xff09;将php代码写入文件 接着访问shell.php 由于存在过滤&#xff0c;需要用到base64加密来使…

SPIRNGBOOT+VUE实现浏览器播放音频流并合成音频

一、语音合成支持流式返回&#xff0c;通过WS可以实时拿到音频流&#xff0c;那么我们如何在VUE项目中实现合成功能呢。语音合成应用非常广泛&#xff0c;如商家广告合成、驾校声音合成、新闻播报、在线听书等等场景都会用到语音合成。 二、VUE下实现合成并使用浏览器播放代码…