当前位置:网站首页>Postgresql中procedure支持事务语法(实例&分析)
Postgresql中procedure支持事务语法(实例&分析)
2022-07-07 02:05:00 【mingjie73】
相关
https://www.postgresql.org/docs/current/plpgsql-transactions.html
实例1:PROCEDURE内部可以使用提交、回滚语句
drop table test1;
create table test1 (a int);
CREATE or replace PROCEDURE transaction_test1()
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO test1 (a) VALUES (2);
COMMIT;
INSERT INTO test1 (a) VALUES (3);
ROLLBACK;
END;
$$;
CALL transaction_test1();
select * from test1;
a
---
2
commit语句都做了什么?
执行上层的事务状态流转函数:
- 执行CommitTransactionCommand
- 执行StartTransactionCommand
static int
exec_stmt_commit(PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
{
if (stmt->chain)
SPI_commit_and_chain();
else
{
SPI_commit();
SPI_start_transaction();
}
...
return PLPGSQL_RC_OK;
}
rollback语句都做了什么?
执行上层的事务状态流转函数:
- 执行AbortCurrentTransaction
- 执行StartTransactionCommand
static int
exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
{
if (stmt->chain)
SPI_rollback_and_chain();
else
{
SPI_rollback();
SPI_start_transaction();
}
...
return PLPGSQL_RC_OK;
}
实例2:PROCEDURE内报错自动回滚已执行的语句
drop table test1;
create table test1 (a int);
CREATE or replace PROCEDURE transaction_test1()
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO test1 (a) VALUES (2);
INSERT INTO test1 (a) VALUES (3);
RAISE division_by_zero;
END;
$$;
CALL transaction_test1();
ERROR: division_by_zero
CONTEXT: PL/pgSQL function transaction_test1() line 5 at RAISE
select * from test1;
a
---
(0 rows)
事务是如何回滚的?
// 触发ereport ERROR
RAISE division_by_zero;
// jump 到:
PostgresMain
if (sigsetjmp(local_sigjmp_buf, 1) != 0)
AbortCurrentTransaction()
走AbortCurrentTransaction触发回滚动作
实例3:PROCEDURE内报错不会滚已经提交的语句
drop table test1;
create table test1 (a int);
CREATE or replace PROCEDURE transaction_test1()
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO test1 (a) VALUES (2);
COMMIT;
INSERT INTO test1 (a) VALUES (3);
RAISE division_by_zero;
END;
$$;
CALL transaction_test1();
select * from test1;
a
---
2
(1 row)
参考实例1的分析结果,commit执行完了会新起一个事务,后面的保存不影响前面已经提交的事务了。
实例4:PROCEDURE包含EXCEPTION的语句块不支持COMMIT
drop table test1;
create table test1 (a int);
CREATE or replace PROCEDURE transaction_test1()
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO test1 (a) VALUES (2);
COMMIT;
INSERT INTO test1 (a) VALUES (3);
RAISE division_by_zero;
EXCEPTION
WHEN division_by_zero THEN
RAISE NOTICE 'caught division_by_zero';
END;
$$;
CALL transaction_test1();
ERROR: cannot commit while a subtransaction is active
CONTEXT: PL/pgSQL function transaction_test1() line 4 at COMMIT
select * from test1;
a
---
(0 rows)
如果走EXCEPTION语句块的话,会把整个block包在一个子事务里面,子事务里面不支持执行commit。
exec_stmt_block
...
if (block->exceptions)
// 启了一个子事务
BeginInternalSubTransaction
PG_TRY()
exec_stmts
PG_CATCH()
// 如果有异常,把整个子事务结束掉
RollbackAndReleaseCurrentSubTransaction
实例5:function是原子的不支持部分提交
drop table test1;
create table test1 (a int);
CREATE or replace function transaction_test1()
returns void
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO test1 (a) VALUES (2);
COMMIT;
INSERT INTO test1 (a) VALUES (3);
ROLLBACK;
END;
$$;
select transaction_test1();
ERROR: invalid transaction termination
CONTEXT: PL/pgSQL function transaction_test1() line 4 at COMMIT
原因:
执行函数前,初始化SPI系统
如果传入的fcinfo->context是一个call context就配置nonatomic
plpgsql_call_handler
nonatomic = fcinfo->context
&& IsA(fcinfo->context, CallContext)
&& !castNode(CallContext, fcinfo->context)->atomic;
SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0))
_SPI_current->atomic = (options & SPI_OPT_NONATOMIC ? false : true);
如果是call procedure语句
_SPI_current->atomic = false;
所以在执行exec_stmt_commit时,不会报错。
exec_stmt_commit
SPI_commit
_SPI_commit
if (_SPI_current->atomic)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
errmsg("invalid transaction termination")));
如果是function会直接报错退出。
边栏推荐
- rt-thread 中对 hardfault 的处理
- Knight defeats demon king (Backpack & DP)
- K8s running Oracle
- VMware安装后打开就蓝屏
- 安装VMmare时候提示hyper-v / device defender 侧通道安全性
- 基于FPGA的VGA协议实现
- QT console output in GUI applications- Console output in a Qt GUI app?
- c面试 加密程序:由键盘输入明文,通过加密程序转换成密文并输出到屏幕上。
- 软件测试的几个关键步骤,你需要知道
- JVM command - jmap: export memory image file & memory usage
猜你喜欢
2022Android面试必备知识点,一文全面总结
ICML 2022 | explore the best architecture and training method of language model
Rk3399 platform development series explanation (WiFi) 5.52. Introduction to WiFi framework composition
dolphinscheduler3.x本地启动
【GNN】图解GNN: A gentle introduction(含视频)
LM小型可编程控制器软件(基于CoDeSys)笔记二十三:伺服电机运行(步进电机)相对坐标转换为绝对坐标
为不同类型设备构建应用的三大更新 | 2022 I/O 重点回顾
Haqi projection Black Horse posture, avec seulement six mois de forte pénétration du marché des projecteurs de 1000 yuans!
Redis (I) -- getting to know redis for the first time
3428. Put apples
随机推荐
Rk3399 platform development series explanation (interruption) 13.10, workqueue work queue
[Shell]常用shell命令及测试判断语句总结
c语言(结构体)定义一个User结构体,含以下字段:
LM small programmable controller software (based on CoDeSys) Note 23: conversion of relative coordinates of servo motor operation (stepping motor) to absolute coordinates
开发者别错过!飞桨黑客马拉松第三期链桨赛道报名开启
JVM monitoring and diagnostic tools - command line
JVM in-depth
Doctoral application | Professor Hong Liang, Academy of natural sciences, Shanghai Jiaotong University, enrolls doctoral students in deep learning
Common problems of caching in high concurrency scenarios
Markdown displays pictures side by side
基本Dos命令
C language interview to write a function to find the first occurrence of substring m in string n.
How to solve sqlstate[hy000]: General error: 1364 field 'xxxxx' doesn't have a default value error
Implementation of VGA protocol based on FPGA
ICML 2022 | 探索语言模型的最佳架构和训练方法
ICML 2022 | explore the best architecture and training method of language model
拼多多败诉:“砍价免费拿”侵犯知情权但不构成欺诈,被判赔400元
Etcd database source code analysis -- starting from the start function of raftnode
tkinter窗口选择pcd文件并显示点云(open3d)
港科大&MSRA新研究:关于图像到图像转换,Fine-tuning is all you need