pg 事务 存储过程_PostgreSQL存储过程BEGIN块的事务处理

有朋友问怎么实现存储过程中的SAVEPOINT,直接调用是不可以的,因为PG不允许事务控制语句出现在存储过程中,但我们还是有办法做到一定程度的模拟。

1、用BEGIN块模拟

随便建个表:

CREATE TABLE a(col1 int);

存储过程如下:

CREATE OR REPLACE FUNCTION ins_t() RETURNS void

AS $$

BEGIN

INSERT INTO a VALUES(100);

BEGIN

INSERT INTO a VALUES(200);

RAISE 'any error';

EXCEPTION

WHEN others THEN

null;

END;

END;

$$ LANGUAGE plpgsql;

测试:

flying=# SELECT ins_t(); ins_t

-------

(1 row)

flying=# SELECT * FROM a;

col1

------

100

(1 row)

可以看到,内嵌BEGIN块中的INSERT操作并没有生效。

2、PL/pgSQL如何实现

块定义在pl_gram.y中,有兴趣可以自己去看,块的执行代码位于 src/pl/plpgsql/src/pl_exec.c。

static int

exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)

{

...

if (block->exceptions)

{

...

BeginInternalSubTransaction(NULL);

...

PG_TRY();

...

PG_CATCH();

...

RollbackAndReleaseCurrentSubTransaction();

...

只有当块定义有EXCEPTION部分,才会出现创建子事务的动作,否则(它对应的else分支内)只会当做普通语句处理。抛出例外时,就把这个子事务会滚掉。

而如果不抛出例外,而是WARNING或者NOTICE之类,也不会引起它的回滚,尝试一下就知道。PG怎么知道要不要回滚,关键在PG_TRY,这个说起来话长,暂时了解到这里足够。

3、没有EXCEPTION处理会怎样

去掉例外处理部分

CREATE OR REPLACE FUNCTION ins_t() RETURNS void

AS $$

BEGIN

INSERT INTO a VALUES(100);

BEGIN

INSERT INTO a VALUES(200);

RAISE 'any error';

END;

END;

$$ LANGUAGE plpgsql;

结果什么都没有,因为它没有启用子事务,所以会全部回滚。

flying=# select ins_t();

ERROR: any error

CONTEXT: PL/pgSQL function ins_t() line 6 at RAISE

flying=# select * from a;

col1

------

(0 rows)

flying=#

4、神奇的PG_TRY和PG_CATCH

它们用到的是sigsetjmp,PG中很多地方用到它,了解这个可能需要一定的汇编语言知识,也需要了解错误抛出机制,有机会再详细讲。

本篇主要是讲在不能使用事务控制语句的情况下,模拟实现ROLLBACK TO SAVEPOINT xxx,以及内部怎样实现,到这里也就结束了,更多细节以后有机会再讲。

从这里也可以看出,PG里边有很多很多值得挖掘的点,所以,没事儿就读代码,一定有惊喜。

上边的过程也很清楚看出,如果需要修改代码实现自己的某个功能,那么:(1)、找到某个现有的相似功能;(2)、阅读关联代码并理解;(3)、能满足自己的需要,调查结束动手实现;(4)、不符合要求返回(1)。为什么要这么做,因为我们并没有PG的开发文档,很难了解里边的API(就像上边的子事务控制)定义,以我的经验这是很好的途径。但这也是有前提的,要么本身很熟悉PG的操作,要么身边有这么一个人,不然也无从下手。如果各位有好的经验,欢迎分享给我。

欢迎关注公众号,文章同步

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值