热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[译稿]PostgreSQL中匿名事务的使用

2019独角兽企业重金招聘Python工程师标准原文链接自主事务是从一个主事务启动的另一个事务,用于执行独立于调用事务提交或取消的SQL命令。最经典的用例是将用

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

原文链接

自主事务是从一个主事务启动的另一个事务,用于执行独立于调用事务提交或取消的SQL命令。

最经典的用例是将用户在数据库上完成的所有操作插入日志记录表,无论事务成功还是失败。使用PostgreSQL,当事务中的某些事务失败时,事务中完成的所有更改都将被取消。出于同样的原因,当自治事务失败时,没有异常会被转发到调用事务,它可以成功执行结束。

译者注: 类似finally, 但是独立的。

try {
}catch {
}
finally {
}

我们可以将自治事务视为一个独立的工作单元,就像在另一个会话中执行SQL语句一样。在这种情况下,在主事务中提交的操作在自主事务中不可见,直到主事务被终止和提交。

在自主事务中执行的SQL操作可以在主事务提交时显示,并且主事务中的隔离级别不是SERIALIZABLE或REPEATABLE READ。

下面是一个非常简单的Oracle函数示例,它使用自主事务独立地记录数据库中执行的所有操作,而不管事务的最终结果是什么。

目前没有办法在PostgreSQL 原生版本中存在(截止2016-08-19, 后面有人提交了补丁)。单个事务中的每个更改都将被取消或随事务一起提交。然而,很长时间以来,有一些解决方案来执行这样的事务。它变得更容易,在PostgreSQL 9.5版本中,旧的解决方案是使用dblink扩展名与后端的专用连接。最新的解决方案是使用pg_background扩展来实现自主事务,内核实现。我在下面的章节中描述两种方式。

“旧的方式”:独立连接:

要使用PostgreSQL获得相同的自治事务行为,您只需打开一个到PostgreSQL的新连接,并在此新会话中执行SQL语句。

为了这个工作,我们通常使用dblink或PL/Proxy contrib模块很长时间。它们都允许创建到PostgreSQL服务器的新连接,并在这个新连接内使用自己的事务执行SQL语句。

例如,Ora2Pg(截止版本17.4)使用带有使用dblink的包装器的pragma AUTONOMOUS_TRANSACTION转换所有Oracle函数或过程。此包装器接受函数的名称并添加一个_atx后缀。

使用上面的Oracle示例,Ora2Pg将首先转换此函数并使用_atx后缀重命名。

CREATE OR REPLACE FUNCTION log_action_atx (username text, event_date timestamp, msg text
) RETURNS VOID AS
$body$
BEGININSERT INTO table_tracking VALUES (nextval('log_seq'), username, event_date, msg);
END;
$body$
LANGUAGE PLPGSQL

然后,它使用将由应用程序或另一个存储过程调用的dblink创建的包装函数。

--
-- dblink wrapper to call function log_action as an autonomous transaction
--
CREATE OR REPLACE FUNCTION log_action (username text, event_date timestamp, msg text
) RETURNS VOID AS
$body$
DECLARE-- Change this to reflect the dblink connection stringv_conn_str text := 'port=5432 dbname=testdb host=localhost user=pguser password=pgpass';v_query text;BEGINv_query := 'SELECT true FROM log_action_atx ( ' || quote_nullable(username) ||',' || quote_nullable(event_date) || ',' || quote_nullable(msg) || ' )';PERFORM * FROM dblink(v_conn_str, v_query) AS p (ret boolean);END;
$body$
LANGUAGE plpgsql SECURITY DEFINER;

此方法工作得很好,但需要一些手动编辑来设置dblink连接参数。 还有一些安全问题,连接密码在功能代码中。 性能也不是最优的。

“新的使用方式”:使用动态后台workder 进程:

希望自从添加动态后台工作人员和Robert Haas的大部分工作以来,可能是因为PostgreSQL v9.5使用pg_background扩展创建自主事务。 此扩展提供了一些其他优势,但本文只是解释如何以自主方式调用函数或SQL语句。

如果我们回到前面的例子,这里是Ora2Pg如何导出函数使用pg_background扩展在即将到来的17.5版本。

--
-- pg_background wrapper to call function log_action as an autonomous transaction
--
CREATE OR REPLACE FUNCTION log_action (username text, event_date timestamp, msg text
) RETURNS VOID AS
$body$
DECLAREv_query text;BEGINv_query := 'SELECT true FROM log_action_atx ( ' || quote_nullable(username) ||',' || quote_nullable(event_date) || ',' || quote_nullable(msg) || ' )';PERFORM * FROM pg_background_result(pg_background_launch(v_query)) AS p (ret boolean);
END;
$body$
LANGUAGE plpgsql SECURITY DEFINER;CREATE OR REPLACE FUNCTION log_action_atx (username text, event_date timestamp, msg text
) RETURNS VOID AS
$body$
BEGININSERT INTO table_tracking VALUES (nextval('log_seq'), username, event_date, msg);
END;
$body$
LANGUAGE PLPGSQL
;

在这里,我们谈到了自动PL/SQL的Oracle代码转换,但是更简单的方法显然是直接调用函数:

CREATE OR REPLACE FUNCTION log_action (username text, event_date timestamp, msg text
) RETURNS text AS
$body$
DECLAREs_id integer;
BEGININSERT INTO table_tracking VALUES (nextval('log_seq'), username, event_date, msg) RETURNING id INTO s_id;RETURN 'Message inserted into table_tracking with id: '|| s_id;
END;
$body$
LANGUAGE plpgsql;

如果我们想等待自治事务的结果并使用结果:

SELECT * FROM pg_background_result(pg_background_launch('SELECT log_action(...)')) AS p (ret text);

否则,对pg_background_launch() 进行简单调用并放在后台执行自主事务。 主事务将继续,而不等待在后台启动的自主事务的结果。

SELECT pg_background_launch('SELECT log_action(...)');

CREATE OR REPLACE FUNCTION test_autonomous_transaction (username text, msg text
) RETURNS text AS
$body$
DECLAREat_pid integer;at_result text;
BEGINSELECT INTO at_pid pg_background_launch('SELECT log_action('||username||','||now()||','||msg)');... do something ...SELECT INTO at_result * FROM pg_background_result(at_pid) as (result text);RETURN at_result;
END;

下面是一个完整的使用Ora2pg 创建的函数

CREATE TABLE table_tracking ( id integer, username text, event_date timestamp, msg text);CREATE SEQUENCE log_seq START 1;CREATE OR REPLACE FUNCTION log_action_atx (username text, event_date timestamp, msg text
) RETURNS VOID AS
$body$
BEGININSERT INTO table_tracking VALUES (nextval('log_seq'), username, event_date, msg);
END;
$body$
LANGUAGE PLPGSQL ;CREATE OR REPLACE FUNCTION log_action (username text, event_date timestamp, msg text
) RETURNS VOID AS
$body$
DECLAREv_query text;
BEGINv_query := 'SELECT true FROM log_action_atx ( ' || quote_nullable(username) || ',' || quote_nullable(event_date) || ',' || quote_nullable(msg) || ' )';PERFORM * FROM pg_background_result(pg_background_launch(v_query)) AS p (ret boolean);
END;
$body$
LANGUAGE plpgsql SECURITY DEFINER;

gilles=# TRUNCATE table_tracking ;
TRUNCATE TABLE
gilles=# ALTER SEQUENCE log_seq restart 1;
ALTER SEQUENCE
gilles=# BEGIN;
BEGIN
gilles=# SELECT * from table_tracking;id | username | event_date | msg
----+----------+------------+-----
(0 ligne)gilles=# SELECT log_action('gilles', 'now', 'Add autonomous_transaction article');log_action
------------(1 ligne)gilles=# SELECT * from table_tracking;id | username | event_date | msg
----+----------+----------------------------+------------------------------------1 | gilles | 2016-08-19 11:55:08.859347 | Add autonomous_transaction article
(1 ligne)gilles=# ROLLBACK;
ROLLBACK
gilles=# SELECT * from table_tracking;id | username | event_date | msg
----+----------+----------------------------+------------------------------------1 | gilles | 2016-08-19 11:55:08.859347 | Add autonomous_transaction article
(1 ligne)

In this last example, we can see that it is perfectly possible to work on something else in the main transaction while the autonomous transaction is running in the background:

在最后一个例子中,我们可以看到,当自主匿名事务在后台运行时,主事务中完全可以在处理其他事情:

gilles=# BEGIN;
BEGIN
gilles=# SELECT * FROM table_tracking;id | username | event_date | msg
----+----------+----------------------------+------------------------------------1 | gilles | 2016-08-19 14:00:12.573144 | Add autonomous_transaction article2 | gilles | 2016-08-19 14:01:20.83565 | Add autonomous_transaction article
(2 lignes)gilles=# SELECT pg_background_launch($$SELECT pg_sleep(30); SELECT log_action('gilles','now','Add autonomous_transaction article');$$);pg_background_launch
----------------------26170
(1 ligne)gilles=# SELECT * FROM table_tracking;id | username | event_date | msg
----+----------+----------------------------+------------------------------------1 | gilles | 2016-08-19 14:00:12.573144 | Add autonomous_transaction article2 | gilles | 2016-08-19 14:01:20.83565 | Add autonomous_transaction article
(2 lignes)... Attente de 30 secondes ...gilles=# SELECT * FROM table_tracking;id | username | event_date | msg
----+----------+----------------------------+------------------------------------1 | gilles | 2016-08-19 14:00:12.573144 | Add autonomous_transaction article2 | gilles | 2016-08-19 14:01:20.83565 | Add autonomous_transaction article3 | gilles | 2016-08-19 14:05:42.181332 | Add autonomous_transaction article
(3 lignes)gilles=# SELECT * FROM pg_background_result(26170) as p (result text);result
-------------------------------------------------Message inserted into table_tracking with id: 3
(1 ligne)gilles=# ROLLBACK;
ROLLBACK

这里,我们在自治事务中添加了等待30秒( ```SELECT pg_sleep(30);), 我们可以看到pg_background_launch() 函数立即返回。 如果我们在主事务中等待30秒,那么我们可以看到, 当自治事务结束时,我们在table_tracking表中有新的条目。 现在我们可以使用pg_background_launch()返回的pid和 pg_background_result()函数来获得自治事务的结果。

这种在后台执行自动事务的特性,可以让你绕过一些PostgreSQL的限制, 比如在事务中运行CREATE INDEX CONCURRENTLY语句。

警告: 需要超级用户来创建此扩展,一旦创建, 任何有权访问数据库的用户将被授予执行这些pg_background_...()函数。 即使对象的ACL被保留,强制要求真正小心数据库访问和定期审计数据库。 要防止所有用户执行这些功能, 最好的办法是将该扩展重定位到专有的模式(schema)下, 只有授权用户才能被授予使用权限。这可以使用以下命令完成:

CREATE SCHEMA bgw_schema;
ALTER EXTENSION pg_background SET SCHEMA bgw_schema;
GRANT USAGE ON SCHEMA bgw_schema TO ;

在由授权用户创建的函数中使用SECURITY DEFINER属性并使用 bgw_schema.pg_background_...()函数将有助于控制安全风险。


转:https://my.oschina.net/innovation/blog/782635



推荐阅读
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 微服务优雅上下线的最佳实践
    本文介绍了微服务上下线的正确姿势,避免使用 kill -9 等粗暴手段,确保服务的稳定性和可靠性。 ... [详细]
  • 包含phppdoerrorcode的词条 ... [详细]
  • C#实现文件的压缩与解压
    2019独角兽企业重金招聘Python工程师标准一、准备工作1、下载ICSharpCode.SharpZipLib.dll文件2、项目中引用这个dll二、文件压缩与解压共用类 ... [详细]
  • Spring Data JdbcTemplate 入门指南
    本文将介绍如何使用 Spring JdbcTemplate 进行数据库操作,包括查询和插入数据。我们将通过一个学生表的示例来演示具体步骤。 ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • 我在使用 AngularJS 的路由功能开发单页应用 (SPA),但需要支持 IE7(包括 IE8 的 IE7 兼容模式)。我希望浏览器的历史记录功能能够正常工作,即使需要使用 jQuery 插件。 ... [详细]
  • javascript分页类支持页码格式
    前端时间因为项目需要,要对一个产品下所有的附属图片进行分页显示,没考虑ajax一张张请求,所以干脆一次性全部把图片out,然 ... [详细]
  • 在JavaWeb开发中,文件上传是一个常见的需求。无论是通过表单还是其他方式上传文件,都必须使用POST请求。前端部分通常采用HTML表单来实现文件选择和提交功能。后端则利用Apache Commons FileUpload库来处理上传的文件,该库提供了强大的文件解析和存储能力,能够高效地处理各种文件类型。此外,为了提高系统的安全性和稳定性,还需要对上传文件的大小、格式等进行严格的校验和限制。 ... [详细]
  • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
    在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
  • 自然语言处理(NLP)——LDA模型:对电商购物评论进行情感分析
    目录一、2020数学建模美赛C题简介需求评价内容提供数据二、解题思路三、LDA简介四、代码实现1.数据预处理1.1剔除无用信息1.1.1剔除掉不需要的列1.1.2找出无效评论并剔除 ... [详细]
  • 在《Linux高性能服务器编程》一书中,第3.2节深入探讨了TCP报头的结构与功能。TCP报头是每个TCP数据段中不可或缺的部分,它不仅包含了源端口和目的端口的信息,还负责管理TCP连接的状态和控制。本节内容详尽地解析了TCP报头的各项字段及其作用,为读者提供了深入理解TCP协议的基础。 ... [详细]
  • 本文详细介绍了在 Oracle 数据库中使用 MyBatis 实现增删改查操作的方法。针对查询操作,文章解释了如何通过创建字段映射来处理数据库字段风格与 Java 对象之间的差异,确保查询结果能够正确映射到持久层对象。此外,还探讨了插入、更新和删除操作的具体实现及其最佳实践,帮助开发者高效地管理和操作 Oracle 数据库中的数据。 ... [详细]
author-avatar
hupi12丨
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有