PostgreSQL Oracle兼容性之 - 函数 自治事务 的实现
发布日期:2021-08-26 15:47:33
浏览次数:2
分类:技术文章
本文共 4866 字,大约阅读时间需要 16 分钟。
使用Oracle的用户,在函数中如果使用了自治事务的话,如果要转到PostgreSQL会遇到很棘手的问题。
因为PostgreSQL的函数是作为一个事务来处理的,要么全部提交,要么全部回滚, 除了exception,每个exception是一个子事务。 因此使用exception可以达到自治事务的目的。 例子1, 使用并行block和嵌套block,来控制子事务层级。 输入参数为block1, block2.1, block2.2, block3.1 。 这些参数代表执行在哪个block出错,出错时对应层级的block的exception会捕获错误,同时处理,然后跳到下一个block继续执行。 如果是外层的block出错,内层还没有被执行的block就没机会执行了。 根据业务需求,调整block层级或嵌套层级,达到目的。 这种用法可以完美的支撑业务的需求。 (除了一种情况不能满足,就是被提交的子事务立刻可以被其他事务可见。这种需求建本文下面的方法,用dblink来满足这种需求即可。)create or replace function ft(err_level text) returns void as $$declarebegin -- block level 1 raise notice 'block level 1'; if (err_level='block1') then raise exception '%', err_level; end if; begin -- block level 2.1 raise notice 'block level 2.1'; -- 请用业务处理SQL代替 if (err_level='block2.1') then raise exception '%', err_level; end if; begin -- block level 3.1 raise notice 'block level 3.1'; if (err_level='block3.1') then raise exception '%', err_level; end if; exception when others then -- you can write catchup any ERROR CODE or ERROR STATE. raise notice 'end block level 3.1'; end; -- end block level 3.1 exception when others then -- you can write catchup any ERROR CODE or ERROR STATE. 回滚block 2.1的业务处理SQL raise notice 'end block level 2.1'; end; -- end block level 2.1 begin -- block level 2.2 raise notice 'block level 2.2'; if (err_level='block2.2') then raise exception '%', err_level; end if; exception when others then -- you can write catchup any ERROR CODE or ERROR STATE. raise notice 'end block level 2.2'; end; -- end block level 2.2 exception when others then -- you can write catchup any ERROR CODE or ERROR STATE. raise notice 'end block level 1';end; -- end block level 1$$ language plpgsql;
测试:
在block 1出错,出错代码后面的代码都不会被执行。postgres=# select ft('block1');NOTICE: block level 1NOTICE: end block level 1 ft ---- (1 row)
在block2.1出错,block 2.1内部出错代码后面的代码都不会被执行。但是同级代码如2.2会被执行。
postgres=# select ft('block2.1');NOTICE: block level 1NOTICE: block level 2.1NOTICE: end block level 2.1NOTICE: block level 2.2 ft ---- (1 row)
在block2.2出错。
postgres=# select ft('block2.2');NOTICE: block level 1NOTICE: block level 2.1NOTICE: block level 3.1NOTICE: block level 2.2NOTICE: end block level 2.2 ft ---- (1 row)
在block3.1出错。
postgres=# select ft('block3.1');NOTICE: block level 1NOTICE: block level 2.1NOTICE: block level 3.1NOTICE: end block level 3.1NOTICE: block level 2.2 ft ---- (1 row)
更直观的例子:
drop table tt;create table tt(id int primary key, info text);insert into tt values(5,'test');create or replace function ft() returns void as $$declarebegin -- block level 1 begin -- block level 2.1 insert into tt values (1,'test'),(2,'test'),(3,'test'); exception when others then raise notice 'rollback block level 2.1'; end; -- end block level 2.1 begin -- block level 2.2 insert into tt values (4,'test'),(5,'test'),(6,'test'); -- 主键冲突, 插入失败, 但是不影响后面的block继续执行. exception when others then raise notice 'rollback block level 2.2'; end; -- end block level 2.2 begin -- block level 2.3 insert into tt values (7,'test'),(8,'test'),(9,'test'); exception when others then raise notice 'rollback block level 2.3'; end; -- end block level 2.3 exception when others then -- you can write catchup any ERROR CODE or ERROR STATE. raise notice 'rollback block level 1';end; -- end block level 1$$ language plpgsql;postgres=# select ft();NOTICE: rollback block level 2.2 ft ---- (1 row)postgres=# select * from tt; id | info ----+------ 5 | test 1 | test 2 | test 3 | test 7 | test 8 | test 9 | test(7 rows)
例子2:
使用dblink,同样需要将需要批量提交的部分写成子函数先。 例如 :create extension dblink;CREATE SERVER fdtest FOREIGN DATA WRAPPER dblink_fdw OPTIONS (hostaddr '127.0.0.1', dbname '函数所在的库名');CREATE USER MAPPING FOR 需要调用函数的用户名 SERVER fdtest OPTIONS (user '需要调用函数的用户名', password '用户密码');GRANT USAGE ON FOREIGN SERVER fdtest TO 需要调用函数的用户名;
函数体
declare dblink_block_res1 record; dblink_block_res2 record;... dblink_block_resn record;... 其他变量定义;begin-- 建立连接if ( dblink_connect('myconn', 'fdtest') <> 'OK' ) then raise notice '连接失败'; return;end if;-- block 1,需要流转的变量通过参数传入下面的函数 select dblink('myconn', 'select func1($1,$2,...)') into dblink_block_res1; -- $1,$2,...使用常数替代, 或动态SQL-- 中间结果判断 if not found then -- dblink调用异常 -- 异常处理 else -- dblink对应子事务已提交 end if;-- block 2,需要流转的变量通过参数传入下面的函数 select dblink('myconn', 'select func2($1,$2,...)') into dblink_block_res2; -- $1,$2,...使用常数替代, 或动态SQL-- 中间结果判断 if not found then -- 远程调用异常 -- 异常处理 else -- dblink对应子事务已提交 end if;......-- block n,需要流转的变量通过参数传入下面的函数 select dblink('myconn', 'select funcn($1,$2,...)') into dblink_block_resn; -- $1,$2,...使用常数替代, 或动态SQL-- 中间结果判断 if not found then -- 远程调用异常 -- 异常处理 else -- dblink对应子事务已提交 end if;......exception when others then...end;
其他参考地址:
转载地址:https://blog.csdn.net/weixin_33890499/article/details/90689835 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
逛到本站,mark一下
[***.202.152.39]2024年04月12日 23时43分01秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
超全深度学习细粒度图像分析:项目、综述、教程一网打尽
2019-04-28
旷视研究院出席全球计算机多媒体顶会ICME 2019
2019-04-28
旷视研究院「技术圆桌派 for PhDs」
2019-04-28
ICCV 2019 | 旷视研究院提出新型抠图方法AdaMatting,实现当前最佳
2019-04-28
活动 | 旷视「智见AI」SpringCamp圆满结营 (附回放链接)
2019-04-28
CVPR 2019 | 旷视研究院提出GIF2Video:首个深度学习GIF质量提升方法
2019-04-28
CVPR 2019 | 旷视研究院提出ML-GCN:基于图卷积网络的多标签图像识别模型
2019-04-28
CVPR 2019 | 旷视研究院提出实时语义分割技术DFANet:高清虚化无需双摄
2019-04-28
CVPR 2019 | 旷视研究院提出新型损失函数:改善边界框模糊问题
2019-04-28
CVPR 2019 | 旷视研究院提出Geo-CNN:建模3D点云的局部几何结构
2019-04-28
旷视研究院ShuffleNet V2斩获VALSE年度杰出学生论文奖
2019-04-28
旷视研究院喜提全球文字检测与识别顶赛ICDAR 2019-ArT两项世界第一
2019-04-28
VALSE 2019 | 旷视研究院奏响学术“华尔兹”,助力谱写中国CV新乐章
2019-04-28
R Talk | 旷视研究院张祥雨:高效轻量级深度模型的研究与实践
2019-04-28
活动 | 「R-Intern 猿力崛起」专场活动回顾
2019-04-28
CVPR 2019 | 旷视研究院提出用于全景分割的端到端闭环网络OANet
2019-04-28
CVPR 2019 | 旷视研究院提出极轻量级年龄估计模型C3AE
2019-04-28
CVPR 2019 | 旷视研究院提出TACNet,刷新时空动作检测技术新高度
2019-04-28