当前位置:网站首页>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会直接报错退出。
边栏推荐
- 学习笔记|数据小白使用DataEase制作数据大屏
- 程序员的日常 | 每日趣闻
- When we talk about immutable infrastructure, what are we talking about
- Party A's requirements for those who have lost 800 yuan
- Symmetric binary tree [tree traversal]
- 请问如何查一篇外文文献的DOI号?
- 缓存在高并发场景下的常见问题
- k8s运行oracle
- c语言面试写一个函数在字符串N中查找第一次出现子串M的位置。
- jmeter 函数助手 — — 随机值、随机字符串、 固定值随机提取
猜你喜欢

生活中的开销,怎么记账合适

哈趣投影黑马之姿,仅用半年强势突围千元投影仪市场!

window下面如何安装swoole

Apache ab 压力测试

ICML 2022 | 探索语言模型的最佳架构和训练方法

Peripheral driver library development notes 43: GPIO simulation SPI driver

基于FPGA的VGA协议实现

直击2022ECDC萤石云开发者大会:携手千百行业加速智能升级

HKUST & MsrA new research: on image to image conversion, fine tuning is all you need

How to keep accounts of expenses in life
随机推荐
Overview of FlexRay communication protocol
高并发大流量秒杀方案思路
Handling hardfault in RT thread
LM小型可编程控制器软件(基于CoDeSys)笔记二十三:伺服电机运行(步进电机)相对坐标转换为绝对坐标
[opencv] morphological filtering (2): open operation, morphological gradient, top hat, black hat
What are the classic database questions in the interview?
字符串常量与字符串对象分配内存时的区别
Shared memory for interprocess communication
360 Zhiyu released 7.0 new products to create an exclusive "unified digital workspace" for the party, government and army, and central and state-owned enterprises
地质学类比较有名的外文期刊有哪些?
Matlab / envi principal component analysis implementation and result analysis
Find duplicate email addresses
PostgreSQL database timescaledb function time_ bucket_ Gapfill() error resolution and license replacement
A very good JVM interview question article (74 questions and answers)
go-microservice-simple(2) go-Probuffer
安装VMmare时候提示hyper-v / device defender 侧通道安全性
CloudCompare-点对选取
JVM in-depth
Swagger3 configuration
[FPGA] EEPROM based on I2C