挖掘PostgreSQL事务的“中间态”----更加严谨的数据一致性?
1.问题
今天在上班途中,中心的妹纸突然找我,非常温柔的找我帮忙看个数据库的报错。当然以我的性格,妹子找我的事情对我来说优先级肯定是最高的,所以立马放下手中的“小事”,转身向妹子走去。具体是一个什么样的问题呢?

可以看到,这是一个postgreSQL的问题,妹子通过python的pscopg2包,通过executemany()的方法,对PostgreSQL数据库进行多条数据的写入操作,但是报了以下错误
psycopg2.errors.InFailedSqlTransaction: current transaction is aborted, commands ignored until end of transaction block
2.问题分析
对这个问题乍看一眼,其实就是当前的事务被中断了,但是具体什么原因,这里并没有告诉我们,所以第一想法,这会不会是触发了什么bug,导致事务突发中断。但是为了解决妹子多条数据插入这个事情,我们还是得确定它问题到底是不是bug。于是,我们还是得先到数据库上看看这个事务的相关日志。
通过对日志的检查,我们看到了以下操作过程:
2023-11-15 15:29:53.682 CST [52096] STATEMENT: data = [(202311,cpu,18%,,),(202311,men,50%,test,),(202311,storage,3%,,)]sql = "insert into aa (a,b,c,d) value (%s,%s,%s,%s)"select * from fk ;
2023-11-15 15:33:52.180 CST [54538] ERROR: syntax error at or near "value" at character 40
2023-11-15 15:33:52.180 CST [54538] STATEMENT: insert into aa (a,b,c,d) value ('202311','cpu','18%','')
2023-11-15 15:34:06.611 CST [54538] ERROR: current transaction is aborted, commands ignored until end of transaction block
从数据库层查看,可以看出,程序通过data定义一个列表,列表中包含了三组数据,并通过insert的sql插入数据库,但是当我们执行到第一个sql时,由于语法错误(insert into … values …的values写成了value),导致插入语句失败,然后报出了我们看到的事务中断的错误。
嗨,看到这里,松了口气,其实就是语法写错导致事务中断而已,不是什么bug嘛,既然事务失败了,那么我们重新发起操作即可。可是妹子又跟我说,后续她改正了错误,然后执行,可还是会报这个错误。
这时,我突然想起在很久之前做过的一些关于pg事务的测试,当时突然测试出一个奇怪的现象,就是当我手动启用一个事务的时候,如果这个事务中的sql执行出错,那么我接着改正sql,继续执行还是会报错,只有当我做了rollback或者commit之后,才能够在这个会话中继续执行sql。
而妹子遇见的这个现象好像和这个确实很像,为了进一步验证想法,我做了之前的实验,过程很简单:
begin;
BEGIN
insert into fk value(now(),'1','2','3');
ERROR: syntax error at or near "value"
LINE 1: insert into fk value(now(),'1','2','3');^
insert into fk values(now(),'1','2','3');
ERROR: current transaction is aborted, commands ignored until end of transaction block
insert into fk values(now(),'3','2','3');
ERROR: current transaction is aborted, commands ignored until end of transaction block
insert into fk values(now(),'3','2','');
ERROR: current transaction is aborted, commands ignored until end of transaction block
select * from fk;
ERROR: current transaction is aborted, commands ignored until end of transaction block很容易的,我们模拟出了这个问题,这个时候我们去看当前的活动会话:postgres=# select pid,usename,application_name,wait_event_type,wait_event,state,query from pg_stat_activity where wait_event_type='Client';pid | usename | application_name | wait_event_type | wait_event | state | query
-------+----------+------------------+-----------------+------------+-------------------------------+-------------------19137 | postgres | psql | Client | ClientRead | idle in transaction (aborted) | select * from aa;
(1 row)此时,我们通过rollback,结束这个事务:rollback;
ROLLBACK再次查看当前活动会话:postgres=# select pid,usename,application_name,wait_event_type,wait_event,state,query from pg_stat_activity where wait_event_type='Client';pid | usename | application_name | wait_event_type | wait_event | state | query
-------+----------+------------------+-----------------+------------+-------+-----------19137 | postgres | psql | Client | ClientRead | idle | rollback;--插入数据测试:
insert into aa values(now(),'1','2','3');
INSERT 0 1--查询表测试:
select * from aa;
...
注:我们知道,在postgresql中,通过psql登陆,事务默认是自动提交的,因此我们不需要在dml操作后,执行commit或者rollback操作,想要关闭事务的自动提交,则有两个方法:
1.通过begin指定开始一个事务块;
2.通过设置AUTOCOMMIT的方式关闭自动提交postgres=# \set AUTOCOMMIT off
postgres=# \echo :AUTOCOMMIT
off
那么上面的现象就很好理解了,我通过begin的方式,开启了一个事务块,在这个事务块中,我执行了一个错误的sql,导致这个事务出现问题中断,而这个事务则进入了一个“中间态”,而会话则是一个idle in transaction (aborted)的状态,此时,只要在这个会话中不论我们执行什么sql,都会报错。而当我做了rollback后,则结束了这个事务,同时会话也成为了idle状态。而我们再次做其他操作时,则是进入了新的事务,并自动提交。
那么,妹子的事情也能解释的通了,通过python等客户端对数据库进行连接操作,默认是开启了一个事务块。妹子在写测试sql的时候,发现了错误并及时修正,但是并未做回滚或提交,结束事务。此时,事务处于“中间态”,会话处于abort。
3.源码证实
虽然妹子的问题解决了,但是实际是不是这样呢?这只能在源码中看看了。在源码中,我找到这么一段代码及描述:

大概意思就是说,当我们在一个事务块中,由于语句造成的中断,虽然我们什么都没做成,但是它还会保持中断状态,直到我们收到一个rollback命令;而当我们从用户客户端收到了rollback命令,那么我们就会讲已经abort的回话清理并恢复到空闲状态。
4.总结
从这个问题中,我们可以看到,PostgreSQL在进行事务操作时候,为了保证事务的一致性,会有一个事务的“中间态”,这里我打个比方,即这个“中间态”保证了PostgreSQL同一个事务中的操作“一荣俱荣,一损俱损”。即在一个事务中,我们可能会存在多个dml操作,而当其中的一个操作失败后,整个事务中的操作都会失败,并且需要手动回滚,而不会存在部分成功部分失败。
对比oracle/mysql,当我们在一个事务中,执行多个dml操作时,正确的操作则会成功(这里会写入到buffer中,旧数据则会在undo中),错误的操作则会失败,从而形成了部分成功的情况。
这样看来,好像PostgreSQL的事务对于整个业务的一致性要更加严谨。比如A给B转钱,那么A的账户要减掉10000,B的账户要增加10000。我们可以将这个过程分为两个update操作,如果按照Oracle/Mysql数据库层面的处理逻辑,但当某些原因,B账户增加10000的update执行失败,此时如果我们做了commit操作,那么则只有A的账户被被更新,B的账户则不变,此时业务则出现了错误。但是如果以PostgreSQL的“中间态”理解,此时A、B的账户则都会回退,看起来更加合理。
当然,这只是我的一些理解,也欢迎各位大佬可以一起交流,指正错误。
相关文章:
挖掘PostgreSQL事务的“中间态”----更加严谨的数据一致性?
1.问题 今天在上班途中,中心的妹纸突然找我,非常温柔的找我帮忙看个数据库的报错。当然以我的性格,妹子找我的事情对我来说优先级肯定是最高的,所以立马放下手中的“小事”,转身向妹子走去。具体是一个什么样的问题呢…...
多种方法实现conda环境迁移
Conda 为包管理器和虚拟环境管理器。在配置完项目环境,进行了编写和测试代码,需要大量数据测试运行时,需要将其移至另一台主机上。Conda 提供了多种保存和移动环境的方法。 方法1: scp拷贝法,直接将envs的环境文件夹…...
C++ string类(一)
1.C语言中的字符串 C语言中,字符串是以\0结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符 OOP(Object Oriented Programming)的思想,而且…...
系统时间和JVM的Date时间不一致问题解决
通过Java得到的时间与操作系统时间不一致,如何修改Java虚拟机时间? 造成这种问题的原因可能是:你的操作系统时区跟你JVM的时区不一致。 你的操作系统应该是中国的时区吧,而JVM的时区不一定是中国时区,你在应用服务器…...
23111701[含文档+PPT+源码等]计算机毕业设计javaweb点餐系统全套餐饮就餐订餐餐厅
文章目录 **项目功能简介:****点餐系统分为前台和后台****前台功能介绍:****后台功能介绍:** **论文截图:****实现:****代码片段:** 编程技术交流、源码分享、模板分享、网课教程 🐧裙:77687156…...
RabbitMQ 部署及配置详解(集群部署)
单机部署请移步: RabbitMQ 部署及配置详解 (单机) RabbitMQ 集群是一个或 多个节点,每个节点共享用户、虚拟主机、 队列、交换、绑定、运行时参数和其他分布式状态。 一、RabbitMQ 集群可以通过多种方式形成: 通过在配置文件中列出群集节点以…...
基于蝠鲼觅食算法优化概率神经网络PNN的分类预测 - 附代码
基于蝠鲼觅食算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于蝠鲼觅食算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于蝠鲼觅食优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要:针对PNN神…...
「分享学习」SpringCloudAlibaba高并发仿斗鱼直播平台实战完结
[分享学习]SpringCloudAlibaba高并发仿斗鱼直播平台实战完结 第一段:简介 Spring Cloud Alibaba是基于Spring Cloud和阿里巴巴开源技术的微效劳框架,普遍应用于大范围高并发的互联网应用系统。本文将引见如何运用Spring Cloud Alibaba构建一个高并发的仿…...
Vue|props配置
props是Vue中用于传递数据的属性。通过在子组件的选项中定义props属性,可以指定子组件可以接收的数据以及其他配置选项。父组件可以通过在子组件上使用特定的属性来传递数据。 目录 目录 App.vue 什么是App.vue 组件引用 props配置 组件复用 案例1:…...
使用Microsoft Dynamics AX 2012 - 2. 入门:导航和常规选项
Microsoft Dynamics AX的核心原则之一是为习惯于Microsoft软件的用户提供熟悉的外观和感觉。然而,业务软件必须适应业务流程,这可能相当复杂。 用户界面和常见任务 在我们开始进行业务流程和案例研究之前,我们想了解一下本章中的常见功能。…...
【代码随想录】算法训练计划21、22
day 21 1、530. 二叉搜索树的最小绝对差 题目: 给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数,其数值等于两值之差的绝对值。 思路: 利用了二叉搜索树的中序遍历特性用了双指…...
java实现钉钉机器人消息推送
项目开发中需要用到钉钉机器人发送任务状态,本来想单独做一个功能就好,但是想着公司用到钉钉机器人发送项目挺多的。所以把这个钉钉机器人抽离成一个组件发布到企业maven仓库,这样可以给其他同事用提高工作效率。 1.目录结构 2.用抽象类&…...
C语言之break continue详解
C语言之break continue 文章目录 C语言之break continue1. break 和 continue2. while语句中的break和continue2.1break和continue举例 3. for语句中的break和continue3.1break和continue举例 1. break 和 continue 循环中break和continue 在循环语句中,如果我达到…...
mysql group by 执行原理及千万级别count 查询优化
大家好,我是蓝胖子,前段时间mysql经常碰到慢查询报警,我们线上的慢sql阈值是1s,出现报警的表数据有 7000多万,经常出现报警的是一个group by的count查询,于是便开始着手优化这块,遂有此篇,记录下…...
Linux的几个常用基本指令
目录 1. ls 指令2.pwd命令3.cd 指令4. touch指令5.mkdir指令6.rmdir指令 && rm 指令7.man指令8.cp指令9.mv指令10.cat指令 1. ls 指令 语法: ls [选项][目录或文件] 功能:对于目录,该命令列出该目录下的所有子目录与文件。对于文件&…...
mac中安装Homebrew
1、Homebrew是什么? 软件安装管理工具 2、先检查电脑中是否已经安装了Homebrew 打开终端输入:brew 提示命令没有找到,说明电脑没有安装Homebrew 如果提示上述图片说明Homebrew已经安装成功 3、安装Homebrew 进入https://brew.sh/ 复制的命…...
Vue23的计算属性(computed)
Vue2&3的计算属性(computed) Vue2的计算属性 原理:data中的属性通过计算得到新的属性,称为计算属性(computed)。computed 具有 getter 和 setter 属性 getter 属性在使用时分别有两次调用:…...
vue3中祖孙组件之间的通信provide和inject
一、在vue3中新增的祖孙之间通信的方式 provide和inject是Vue中的两个相关功能,它们一起提供了一种祖孙组件之间共享数据的方式。父组件可以使用provide来提供数据,而子孙组件可以使用inject来接收这些数据。 二、使用 父组件中部分代码 <script&g…...
月影下的时光机:Python中的日期、时间、农历、节气和时区探秘
前言 在现代软件开发中,对日期、时间和时区的准确处理至关重要。无论是全球化应用的开发,还是与时序数据相关的任务,都需要强大而灵活的工具。Python作为一门流行的编程语言,提供了丰富的标准库和第三方库,使得处理日…...
【Bazel】Bazel 学习笔记
本文简单记录下 Bazel 使用过程中的一些知识点。 目录 文章目录 目录Bazel 目录结构BUILD 构建规则常用构建规则 Bazel 命令bazel buildbazel query Mac 安装 Bazel Bazel 是谷歌推出的一个开源的构建工具,工作原理与 make、maven 或 gradle 等其他构建工具类似。但…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...
