当前位置:网站首页>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会直接报错退出。
边栏推荐
- 3531. 哈夫曼树
- c语言面试写一个函数在字符串N中查找第一次出现子串M的位置。
- 基于ADAU1452的DSP及DAC音频失真分析
- 基于FPGA的VGA协议实现
- vim映射大K
- C language sorting (to be updated)
- Oracle迁移中关于大容量表使用数据泵(expdp、impdp)导出导入容易出现的问题和注意事项
- Common problems of caching in high concurrency scenarios
- Handling hardfault in RT thread
- Peripheral driver library development notes 43: GPIO simulation SPI driver
猜你喜欢

Redis (II) - redis General Command

Jcmd of JVM command: multifunctional command line

3531. Huffman tree

What are the classic database questions in the interview?

面试中有哪些经典的数据库问题?

Audio distortion analysis of DSP and DAC based on adau1452

LM小型可编程控制器软件(基于CoDeSys)笔记二十三:伺服电机运行(步进电机)相对坐标转换为绝对坐标

Rk3399 platform development series explanation (WiFi) 5.52. Introduction to WiFi framework composition

JVM command - jmap: export memory image file & memory usage

Ha Qu projection dark horse posture, only half a year to break through the 1000 yuan projector market!
随机推荐
当我们谈论不可变基础设施时,我们在谈论什么
window下面如何安装swoole
3531. 哈夫曼树
How to use wechat cloud hosting or cloud functions for cloud development of unapp development applet
【GNN】图解GNN: A gentle introduction(含视频)
jmeter 函数助手 — — 随机值、随机字符串、 固定值随机提取
Basic DOS commands
Rk3399 platform development series explanation (interruption) 13.10, workqueue work queue
Rk3399 platform development series explanation (WiFi) 5.53, hostapd (WiFi AP mode) configuration file description
Matlab / envi principal component analysis implementation and result analysis
高并发大流量秒杀方案思路
HKUST & MsrA new research: on image to image conversion, fine tuning is all you need
3428. 放苹果
C language interview to write a function to find the first occurrence of substring m in string n.
Markdown 并排显示图片
Calculation model FPS
Redis (II) - redis General Command
Crudini profile editing tool
哈趣投影黑马之姿,仅用半年强势突围千元投影仪市场!
win系统下安装redis以及windows扩展方法