How to make PostgreSQL functions atomic?
Question:
How to make PostgreSQL functions atomic?
Assume I have some PostgreSQL functions like the following:
CREATE FUNCTION insertSth() RETURNS void AS $$
BEGIN
INSERT INTO ...;
END;
CREATE FUNCTION removeSthAfterSelect() RETURNS TABLE(...) AS $$
BEGIN
SELECT id INTO some_id ...;
RETURN QUERY SELECT * FROM ...;
DELETE FROM ... WHERE id = some_id;
END;
CREATE FUNCTION justDeleteSth() RETURNS void AS $$
BEGIN
DELETE FROM ...;
END;
CREATE FUNCTION justSelectSth() RETURNS TABLE(...) AS $$
BEGIN
RETURN SELECT * FROM ...;
END;
From my understanding PostgresSQL functions insertSth, justDeleteSth and justSelectSth are going to be executed atomically(?). So parallel executions of them won't mess anything up.
But for removeSthAfterSelect if there is a parallel execution it could be that SELECT id INTO some_id .. finds something, then concurrently another transaction calls justDeleteSth and deletes the row with id = someId, so when the transaction continues it won't delete anything here: DELETE FROM ... WHERE id = some_id; meaning it messes things up.
Is this the case? Is there a way to avoid this problem? E.g. by saying that removeSthAfterSelectshould be executed atomically?
A transaction has the property of atomic commit, i.e. the entire transaction is guaranteed to take effect, or none of it does.
That doesn't mean that transactions can't interact. In particular, in READ COMMITTED mode a transaction committing midway though another transaction can have visible effects. Even without that, concurrently anomalies are possible and normal. See the PostgreSQL chapter on concurrency control, particularly the transaction isolation section. Statements in functions are no more immune to concurrency issues than standalone statements.
Even within a single statement it's possible to have concurrency issues. Statements are not magically atomic. People often think that if they can pack everything into a single query using CTEs, subqueries, etc, it'll be magically immune to concurrency issues. That is not the case.
There's no function label to say "execute this atomically" because the concept you're looking for just doesn't exist in the DBMS. The closest you'll get is to LOCK TABLE ... IN ACCESS EXCLUSIVE all tables that the function uses, so that nothing else can touch them. That is usually rather excessive and unnecessary if you can reason effectively about concurrency and transaction isolation.
It's difficult to be more specific because you're using a very generalised example with all the details left out. For example, why does it matter if you attempt to delete the row twice?
A few concepts you should study:
- Snapshots
READ COMMITTEDvsSERIALIZABLEtransaction isolation- Row and table level locks, both implicit (e.g. those taken by DML) and explicit (e.g.
SELECT ... FOR UPDATE) - Transaction visibility
- Predicate re-checks after a DML statement finishes waiting on a lock
As one example of concurrency in action, take a look at the upsert problem.
But for removeSthAfterSelect if there is a parallel execution it could be that SELECT id INTO some_id .. finds something, then concurrently another transaction calls justDeleteSth and deletes the row with id = someId, so when the transaction continues it won't delete anything here: DELETE FROM ... WHERE id = some_id; meaning it messes things up.
You're talking as if one transaction stops and the other runs, then the first continues. That's often not the case; things can run completely concurrently, with many statements happening truly simultaneously.
The main thing that limits that is row level locking. In this case, there's a race condition, as both DELETEs try to acquire the row update lock for the row. Whichever gets it will continue and delete the row. The other DELETE gets stuck on the row lock until the winning transaction commits or rolls back. If it rolls back, it's as if nothing happened and the waiting transaction continues as normal. If the winning transaction commits the delete, the waiting transaction sees the lock has been released, and (in READ COMMITTED mode) re-checks the WHERE clause predicate to make sure the row is still matched, discovers it doesn't exist anymore, and carries on without an error as it's not an error to delete zero rows.
In PL/PgSQL you can check the affected row count if you want to enforce that a statement affect exactly one row, and RAISE EXCEPTION if it didn't match the expected affected rows. There's also INTO STRICT for SELECT.
How to make PostgreSQL functions atomic?的更多相关文章
- WRITING POSTGRESQL TRIGGERS IN GO
转自:https://www.opsdash.com/blog/postgresql-triggers-golang.html 可以学习如何使用golang 编写pg extension Trigge ...
- C-Language Functions
转自:https://www.postgresql.org/docs/9.6/xfunc-c.html 可以作为学习基于c编写pg extension 的资料 36.9. C-Language Fun ...
- postgresql 创建函数
One of the most powerful features of PostgreSQL is its support for user-defined functions written in ...
- postgresql spi开发笔记
#include "postgres.h" #include "fmgr.h" #include <string.h> #ifdef PG_MODU ...
- PDO和PDOStatement类常用方法
PDO — PDO 类 PDO::beginTransaction — 启动一个事务 PDO::commit — 提交一个事务 PDO::__construct — 创建一个表示数据库连接的 PDO ...
- 转---redshift database ---学习
摘自他人 前沿 根据最近一段时间对redshift的研究,发现一些特性比较适合我们当前的业务. 1 比如它的快速恢复能力,因为这一点,我们可以尽量在redshit里面存放一定生命周期的数据,对过期的数 ...
- A Deep Dive into PL/v8
Back in August, Compose.io announced the addition of JavaScript as an internal language for all new ...
- PostgreSQL 窗口函数 ( Window Functions ) 如何使用?
一.为什么要有窗口函数 我们直接用例子来说明,这里有一张学生考试成绩表testScore: 现在有个需求,需要查询的时候多出一列subject_avg_score,为此科目所有人的平均成绩,好跟每个人 ...
- Linux -- GCC Built-in functions for atomic memory access
下列内建函数旨在兼容Intel Itanium Processor-specific Application Binary Interface, section 7.4. 因此,这些函数区别于普通的G ...
随机推荐
- C++ code:函数指针参数
函数指针除了进行参数传递外,还承接申请的存储空间.释放空间等.而函数指针则主要是用来进行参数传递的,就像引用一样. 例如,我们来看一下函数指针的传递工作.在标准排序算法sort中,对于所提的整数容器v ...
- WCF客户端从服务器下载数据
1.打开VS选择控制台项目新建一个解决方案Server,然后添加两个类库Contract和Service. 2.在Contract中添加一个接口IFileDownload using System; ...
- 如何重置mate的面板到初始化时的默认设置?
在你的任何终端中敲入如下命令: gsettings reset-recursively org.mate.panel
- hdu 4707 仓鼠 记录深度 (BFS)
题意:linji的仓鼠丢了,他要找回仓鼠,他在房间0放了一块奶酪,按照抓鼠手册所说,这块奶酪可以吸引距离它D的仓鼠,但是仓鼠还是没有出现,现在给出一张关系图,表示各个房间的关系,相邻房间距离为1,而且 ...
- Spring之hello world(Spring入门)
spring各个版本中: 在3.0以下的版本,源码有spring中相关的所有包[spring功能 + 依赖包] 如2.5版本: 在3.0以上的版本,源码中只有spring的核心功能包[没有依赖包] ( ...
- mysql 增加只读用户查询指定表
GRANT SELECT ON dsideal_db.t_base_organization TO 'guanli'@'%' IDENTIFIED BY '123456';GRANT SELECT O ...
- #11 UVA 10529 Dumb Bones
题意: 放一堆排,每放一张,有pa的概率让左边的全倒,有pb的概率让右边全倒 问在最优策略下,最少要放几张才能摆放出n张 1<=n<=1000 题解: 这题应该还是很经典的 首先是期望部分 ...
- A. 【UR #17】滑稽树上滑稽果
题解: 首先很显然的是这是一条链(特殊数据说是链是故意让人迷茫的??) 然后 自己就开始yy 觉得每一次是加入一个使得当前值最小的数 然而这tm又是特殊数据?? 那就写一波发现是错的 考虑一下特殊数据 ...
- POJ2065 SETI 高斯消元
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ2065 题意概括 多组数据,首先输入一个T表示数据组数,然后,每次输入一个质数,表示模数,然后,给出一 ...
- 二分搜索-HihoCoder1139
题目描述: 由于自己“想得太多”,导致自己读了半天题才理解了题意.我还以为索敌值会随着每一次到达战略点而减小,结果题意是索敌值是固定了的,并不会改变. 如下是我对题目中第一个案例的分析: 每个圆圈代表 ...