PostgreSQL函数自动Commit/Rollback所带来的问题

一、综述

今天在PostgreSQL遇到一个奇怪的现象,简而言之,是想用函数(存储过程)实现插入记录,整个过程没报错但事后却没找到记录!忙活半天,才发现原因是PostgreSQL函数(存储过程)有自动COMMIT或ROLLBACK的特殊规定。

二、问题重现

以下用示例表和示例代码来重现该问题。

create table t1 
(ID int not null primary key,name varchar(20)
);

涉及的存储过程是从oracle那边直接拷贝过来后再修改过的,原先是动态SQL,这里简化为静态SQL。注意其中有个commit;根据PostgreSQL的要求,对事务增加begin...exception...end,否则会有错误或警告。示例脚本代码为:

复制代码

create or replace function p1(pid int, pname varchar)
returns void as $$
beginbegin             --pg对事务的要求insert into t1 values(pid, pname);commit;exception      when others thenend;              --pg对事务的要求
end;
$$ language plpgsql;

依次执行脚本创建存储过程、调用存储过程、查找示例表,结果如下: 

postgres=# \i test1.sql
CREATE FUNCTION
postgres=# select p1(1, 'abc');p1
----
(1 行记录)postgres=# select * from t1;

  id | name
  ----+------
  (0 行记录)

要插入的记录并不存在!惊喜不惊喜?意外不意外?

三、原因分析及解决

仔细查找有关资料,发现有这么一个解释:

Functions and trigger procedures are always executed within a transaction established by an outer 
query — they cannot start or commit that transaction, since there would be no context for them to 
execute in. However, a block containing an EXCEPTION clause effectively forms a subtransaction that 
can be rolled back without affecting the outer transaction.

其意义是PostgreSQL的函数总是默认为一个事务,总是自动Commit或Rollback。

其实一开始没增加begin...exception...end时,PostgreSQL报错“can't begin/end transaction  in pl/pgsql”,已经隐含了这层信息。只是脑子里还是延续Oracle的习惯,而画蛇添足了。

于是,修改存储过程的脚本,按最简单的法子来

create or replace function p2(pid int, pname varchar)
returns void as $$
begininsert into t1 values(pid, pname);
end;
$$ language plpgsql;

为验证此说法是否正确,在再次创建函数、调用函数后,增加一个回滚(事先已设置AutoCommit为false)的操作,然后再查询记录:

postgres=# \i test1.sql
CREATE FUNCTION
postgres=# select p2(1, 'abc');p2
----
(1 行记录)postgres=# rollback;
WARNING:  there is no transaction in progress
ROLLBACK
postgres=# select * from t1;id | name
----+------1 | abc
(1 行记录)

复制代码

四、总结

Oracle是可以在存储过程或函数里指定Commit/Rollback的,如果没有,则外部调用者可以回滚存储过程内部的操作。

但在PostgreSQL,函数(存储过程)总是自动将其所有操作当作一个事务,外部无法对内部操作提交或回滚。

问题好像已经解决,但留有一个疑问没弄明白,为什么PostgreSQL允许在函数体中加关于事务的begin...exception...end,但结果却好像是没提交?

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

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

相关文章

linux 进程补充

环境变量 基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如:我们在编写C/C代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪 里,但是照样可以链接成功&#…

Spring Boot常用注解深度解析:从入门到精通

今天,这篇文章带你将深入理解Spring Boot中30常用注解,通过代码示例和关系图,帮助你彻底掌握Spring核心注解的使用场景和内在联系。 一、启动类与核心注解 1.1 SpringBootApplication 组合注解: SpringBootApplication Confi…

前部分知识复习05

一、多级渐远贴图MipMap 选择贴图,可以勾选贴图的多级渐远效果 [IntRange]_MipMap("MipMap",Range(0,12))0 //多级渐远贴图的LOD调节滑杆 _MipMapTexture("MipMapTexture",2D)"white"{} //定义多级渐远贴图 多级渐远贴图的采样…

解锁反序列化漏洞:从原理到防护的安全指南

目录 前言 一、什么是反序列化 二、反序列化漏洞原理 三、反序列化漏洞的危害 (一)任意代码执行 (二)权限提升 (三)数据泄露与篡改 四、常见的反序列化漏洞场景 (一)PHP 反…

理解 C 与 C++ 中的 const 常量与数组大小的关系

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 💯前言💯数组大小的常量要求💯C 语言中的数组大小要求💯C 中的数组大小要求💯为什么 C 中 const 变量可以作为数组大小💯进一步的…

MAC OS安装Homebrew

文章目录 1.下载Homebrew2.完成安装3.验证安装4.更新 Homebrew作为一个包管理器,提供了一种简便的方式来安装、更新和卸载各种命令行工具和应用程序。相比于手动下载和编译源代码,或者从不同的网站下载安装包,使用Homebrew可以显著减少这些操…

深入解析:如何利用 Python 爬虫获取商品 SKU 详细信息

在电商领域,SKU(Stock Keeping Unit,库存单位)详细信息是电商运营的核心数据之一。它不仅包含了商品的规格、价格、库存等关键信息,还直接影响到库存管理、价格策略和市场分析等多个方面。本文将详细介绍如何利用 Pyth…

OKHttp拦截器解析

OKHttp涉及到拦截器大概的执行步骤为: 1.通过newCall生成RealCall对象 具体代码如下: Override public Call newCall(Request request) {return new RealCall(this, request, false /* for web socket */);}2.调用Call的execute方法 当然这也可以是执…

深度学习系列--04.梯度下降以及其他优化器

目录 一.梯度概念 1.一元函数 2.二元函数 3.几何意义上的区别 二.梯度下降 1.原理 2.步骤 3.示例代码(Python) 4.不同类型的梯度下降 5.优缺点 三.动量优化器(Momentum) 适用场景 1.复杂地形的优化问题 2.数据具有噪声的问…

编程AI深度实战:给vim装上AI

系列文章: 编程AI深度实战:私有模型deep seek r1,必会ollama-CSDN博客 编程AI深度实战:自己的AI,必会LangChain-CSDN博客 编程AI深度实战:给vim装上AI-CSDN博客 编程AI深度实战:火的编程AI&…

深入解析 JPA 的 EntityManager#refresh 方法

在 Java 持久化领域,JPA(Java Persistence API)是一个非常重要的技术,它为开发者提供了一种便捷的方式来操作数据库。今天,我们来深入探讨一下 JPA 中 EntityManager#refresh 方法的使用和原理。 一、refresh 方法的作…

2025年2月6日(anaconda cuda 学习 基本命令)

查看电脑的显卡型号是否支持CUDA的安装 https://developer.nvidia.com/zh-cn/cuda-gpus 查看可以安装的CUDA版本 https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html CUDA安装地址 https://developer.nvidia.com/cuda-toolkit-archive Anaconda下载地址 htt…

自动化构建——make/makefile

目录 背景使用推导过程如果多个文件呢?? 背景 会不会写makefile,从侧面可以说明一个人是否具有完成大型工程的能力makefile带来的好处就是——”自动化编译“,一旦写好,只需要一个make命令,整个工程完全自…

深度整理总结MySQL——SQL的执行顺序和流程

SQL的执行顺序和流程 SQL的执行顺序执行一条select语句,发生了什么呢连接器查询缓存解析SQL执行SQL预处理器优化器执行器 总结 SQL的执行顺序 这是一条标准的查询语句: 但实际上并不是从上到下去解析的,真实的执行顺序是: 我们先执行from,join来确定表之间的连接关系&#x…

R语言 | 使用 ComplexHeatmap 绘制热图,分区并给对角线分区加黑边框

目的:画热图,分区,给对角线分区添加黑色边框 建议直接看0和4。 0. 准备数据 # 安装并加载必要的包 #install.packages("ComplexHeatmap") # 如果尚未安装 library(ComplexHeatmap)# 使用 iris 数据集 #data(iris)# 选择数值列&a…

11 享元(Flyweight)模式

享元模式 1.1 分类 (对象)结构型 1.2 提出问题 做一个车管所系统,将会产生大量的车辆实体,如果每一个实例都保存自己的所有信息,将会需要大量内存,甚至导致程序崩溃。 1.3 解决方案 运用共享技术有效…

脚本批量重启openstack虚拟机并加上启动编号、脚本批量验证openstack虚拟机状态并加上编号

文章目录 说明脚本批量重启openstack虚拟机并加上启动编号脚本准备uuid文件准备测试脚本批量验证openstack虚拟机虚拟机状态为并加上编号脚本准备uuid文件准备测试说明 用uuid批量重启openstack虚拟机并带上编号,执行效果分别如下# 重启 [root@controller01 ccx]# sh start_fo…

Jetpack ViewModel

private val deviceViewModel: IDeviceViewModel by viewModels<DeviceViewModel>() 这句代码是 Jetpack ViewModel 在 Fragment 或 Activity 中的标准用法&#xff0c;它的作用是 创建并获取 ViewModel 实例&#xff0c;同时确保 ViewModel 的生命周期与 UI 组件保持一…

线程池如何知道一个线程的任务已经执行完成

一、线程池内部任务执行状态监控 在线程池内部&#xff0c;当我们提交一个任务后&#xff0c;线程池会调度一个工作线程来执行该任务的run方法。确实&#xff0c;当run方法正常结束时&#xff0c;意味着任务已经完成。线程池中的工作线程是同步调用任务的run方法&#xff0c;并…

2025年Android NDK超全版本下载地址

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…