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 insertSthjustDeleteSth 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?

--------------------------------------------------------------------------------------------------------------------------------------------
 
Answer:

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 COMMITTED vs SERIALIZABLE transaction 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?的更多相关文章

  1. WRITING POSTGRESQL TRIGGERS IN GO

    转自:https://www.opsdash.com/blog/postgresql-triggers-golang.html 可以学习如何使用golang 编写pg extension Trigge ...

  2. C-Language Functions

    转自:https://www.postgresql.org/docs/9.6/xfunc-c.html 可以作为学习基于c编写pg extension 的资料 36.9. C-Language Fun ...

  3. postgresql 创建函数

    One of the most powerful features of PostgreSQL is its support for user-defined functions written in ...

  4. postgresql spi开发笔记

    #include "postgres.h" #include "fmgr.h" #include <string.h> #ifdef PG_MODU ...

  5. PDO和PDOStatement类常用方法

    PDO — PDO 类 PDO::beginTransaction — 启动一个事务 PDO::commit — 提交一个事务 PDO::__construct — 创建一个表示数据库连接的 PDO ...

  6. 转---redshift database ---学习

    摘自他人 前沿 根据最近一段时间对redshift的研究,发现一些特性比较适合我们当前的业务. 1 比如它的快速恢复能力,因为这一点,我们可以尽量在redshit里面存放一定生命周期的数据,对过期的数 ...

  7. A Deep Dive into PL/v8

    Back in August, Compose.io announced the addition of JavaScript as an internal language for all new ...

  8. PostgreSQL 窗口函数 ( Window Functions ) 如何使用?

    一.为什么要有窗口函数 我们直接用例子来说明,这里有一张学生考试成绩表testScore: 现在有个需求,需要查询的时候多出一列subject_avg_score,为此科目所有人的平均成绩,好跟每个人 ...

  9. Linux -- GCC Built-in functions for atomic memory access

    下列内建函数旨在兼容Intel Itanium Processor-specific Application Binary Interface, section 7.4. 因此,这些函数区别于普通的G ...

随机推荐

  1. laravel job 与 event 的区别

    job 是异步执行.适合耗时长的任务.例如,批量发送邮件,短信. event 是在 request 的生命周期内执行.适合耗时短的操作.例如,更改数据字段状态. 但是, event 的好处是,可以复用 ...

  2. python 全栈开发,Day106(结算中心(详细),立即支付)

    昨日内容回顾 1. 为什么要开发路飞学城? 提供在线教育的学成率: 特色: 学,看视频,单独录制增加趣味性. 练,练习题 改,改学生代码 管,管理 测,阶段考核 线下:8次留级考试 2. 组织架构 - ...

  3. websocket+Django+python+paramiko实现web页面执行命令并实时输出

    一.概述 WebSocket WebSocket的工作流程:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过 T ...

  4. POJ 3579 3685(二分-查找第k大的值)

    POJ 3579 题意 双重二分搜索:对列数X计算∣Xi – Xj∣组成新数列的中位数 思路 对X排序后,与X_i的差大于mid(也就是某个数大于X_i + mid)的那些数的个数如果小于N / 2的 ...

  5. linux shell cut 命令

    cut命令 cut命令用于从文件或者标准输入中读取内容并截取每一行的特定部分并送到标准输出. 截取的方式有三种:一是按照字符位置,二是按照字节位置,三是使用一个分隔符将一行分割成多个field,并提取 ...

  6. char *s 与 char s[ ]的区别

    程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其 操作方式类似于数据结构中的栈. 2.堆区( ...

  7. P2326 AKN’s PPAP

    P2326 AKN’s PPAP比较裸的贪心从高位向下枚举,如果当前位为1的个数大于1,ans+=(1<<i),然后从这些数中再向下枚举. #include<iostream> ...

  8. MIT-6.824 Raft协议

    摘要 raft是一种比paxos容易理解的一致性算法,实现起来比paxos简单许多.本文前部分描述算法的细节,后部分尝试探讨下该算法的原理. 算法描述 raft算法之所以简单的原因之一是它将问题分解成 ...

  9. 一次webapck4 配置文件无效的解决历程

    前言 升级webpack4,一定要去看文档,特别是更新说明,不要自持用过原本webpack就自己开始折腾.折腾到后面,可能就默默流下眼泪了. webpack4的变化 webpack-cli抽离 web ...

  10. Node.js之图片上传

    本文用node进行图片上传主要借助formidable插件,具体使用步骤如下: 1.安装formidable插件 npm install formidable -g 2.引入依赖包 const for ...