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. java多线程快速入门(十四)

    使用atomicInteger解决了原子性问题(AtomicInteger保证每次只能一个线程操作count) package com.cppdy; import java.util.concurre ...

  2. 自己理解Java中的lambda

    lambda是什么 "Lambda 表达式"(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lam ...

  3. iOS学习笔记之UITableViewController&UITableView

    iOS学习笔记之UITableViewController&UITableView 写在前面 上个月末到现在一直都在忙实验室的事情,与导师讨论之后,发现目前在实验室完成的工作还不足以写成毕业论 ...

  4. 步步为营-59-svn简介

    说明:版本控制器Svn的使用,安装教程不再多说 VisualSVN-Server--项目经理 TortoiseSVN--右击的时候显示 VisualSVN-- visual studio中使用 1 搭 ...

  5. JavaScript常见的假值

    值 说明 var a=false; 值等于false(假) var a =0; 值等于0 var a=''; 空的字符串 var a=10/'abc' NaN var a; 未赋值变量

  6. BZOJP1899ZJOI2004

    老早的一道水题 题意: 上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂.这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭.由于每个人的口味(以及胃口)不同,所以 ...

  7. zprofiler三板斧解决cpu占用率过高问题

    zprofiler三板斧解决cpu占用率过高问题  九居 浏览 171 2015-04-08 14:11:58 发表于:JVM性能与调试平台   zprofiler   上周五碰到了一个线上机器cpu ...

  8. Scala入门教程---《chang哥教你一天搞定Scala》

    <chang哥教你一天搞定Scala> /** * <chang哥教你一天搞定Scala> * scala是一门多范式编程语言,集成了面向对象编程和函数式编程等多种特性. * ...

  9. android和java以太坊开发区块链应用使用web3j类库

    如何使用web3j为Java应用或Android App增加以太坊区块链支持,教程内容即涉及以太坊中的核心概念,例如账户管理包括账户的创建.钱包创建.交易转账,交易与状态.智能合约开发与交互.过滤器和 ...

  10. Mac电脑如何设置DHCP

    通过设置MAC电脑的DHCP服务器可以为局域网内的其它设备自动分配IP地址,还能把物理地址和IP地址绑定起来,限制IP地址的获取.   OS X 10.11或以上版本已内置DHCP服务器软件,即boo ...