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 ...
随机推荐
- LeetCode(62):不同路径
Medium! 题目描述: 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为“F ...
- tomcat 拒绝服务
一 尝试重新下载二进制安装包安装包 wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-9/v9.0.16/bin/apache-tomcat-9.0 ...
- laravel 事件广播
Laravel 5.1 之中新加入了事件广播的功能,作用是把服务器中触发的事件通过websocket服务通知客户端,也就是浏览器,客户端js根据接受到的事件,做出相应动作.本文会用简单的代码展示一个事 ...
- SPLAY,LCT学习笔记(四)
前三篇好像变成了SPLAY专题... 这一篇正式开始LCT! 其实LCT就是基于SPLAY的伸展操作维护树(森林)连通性的一个数据结构 核心操作有很多,我们以一道题为例: 例:bzoj 2049 洞穴 ...
- python接口自动化测试四:代码发送HTTPS请求
HTTPS: get: url = 'https://www.juhe.cn/docs/api/id/39' r = requests.get(url) # ...
- 如何将Oracle 当前日期加一天、一分钟
在Oralce中我发现有add_months函数,加天数N可以用如下方法实现,select sysdate+N from dual sysdate+1 加一天sysdate+1/24 加1小时sysd ...
- SG 大法(Sprague-Grundy函数)
SG函数的定义: g(x) = mex ( sg(y) |y是x的后继结点 ) 其中mex(x)(x是一个自然是集合)函数是x关于自然数集合的补集中的最小值,比如x={0,1,2,4,6} 则mex( ...
- hdu 4707 仓鼠 记录深度 (BFS)
题意:linji的仓鼠丢了,他要找回仓鼠,他在房间0放了一块奶酪,按照抓鼠手册所说,这块奶酪可以吸引距离它D的仓鼠,但是仓鼠还是没有出现,现在给出一张关系图,表示各个房间的关系,相邻房间距离为1,而且 ...
- Python 时间获取
摘自:http://www.jb51.net/article/91365.htm 摘自:https://www.cnblogs.com/liuq/p/6211005.html 一.在python中,除 ...
- BZOJ1293 [SCOI2009]生日礼物 离散化
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1293 题意概括 彩珠有N个,分为K种.每一个彩珠有一个对应的坐标.坐标上可以没有彩珠,多个彩珠也可 ...