Gaj*_*jus 9 postgresql transaction
我需要我的程序代码来确保逻辑的某些部分在事务中执行。
什么查询会告诉我当前的交易 ID/其他信息,使我能够确定我是否处于交易中?
BEGIN;
-- How to check if I am in a transaction?
COMMIT;
Run Code Online (Sandbox Code Playgroud)
Gaj*_*jus 10
一个简单的方法是now()比较statement_timestamp()。
now()给出当前日期和时间(当前事务的开始)。statement_timestamp()给出当前日期和时间(当前语句的开始)。例子:
SELECT now() = statement_timestamp();
-- TRUE
BEGIN;
SELECT now() = statement_timestamp();
-- FALSE
Run Code Online (Sandbox Code Playgroud)
另一种选择是执行两个查询:
SELECT txid_current();
SELECT txid_current();
Run Code Online (Sandbox Code Playgroud)
并比较所得的 xid。如果相同,那么您就处于交易状态。
后一种方法的缺点是,每次都会txid_current()增加 xid 值,并将进一步推进您的环绕。
从 PostgreSQL 版本 10 及更高版本(即截至 2022 年 5 月的所有txid_current()支持版本)开始,除了@Gajus 已经提到的功能之外,还有一个txid_current_if_assigned()函数,如果没有 [transaction] ID,则返回 \xe2\x80\x9cNULL分配了 \xe2\x80\x9d ,允许您 \xe2\x80\x9c 避免不必要地消耗 XID\xe2\x80\x9d (这是 @Gajus 在 2018 年的回答中暗示的问题)。
事实上,从 PostgreSQL 13 开始,这些txid_带 - 前缀的函数已被弃用pg_current_xact_id(),取而代之的是pg_current_xact_id_if_assigned()。
如果您只是想知道当前是否在事务中,最好使用pg_current_xact_id_if_assigned()比pg_current_xact_id(),因为根据经验,您希望避免不必要的 XID 消耗。例如,GitLab遇到了问题,因为他们过于广泛地使用保存点。
然而,警告也适用于pg_current_xact_id_if_assigned(). 只要事务中没有写入任何内容,它就会返回NULL,因为 PostgreSQL 在发生写入操作之前不会分配事务 ID。一种可能的解决方法是创建一个绑定事务的临时表:
SELECT pg_current_xact_id_if_assigned() IS NOT NULL AS is_transaction;\nRun Code Online (Sandbox Code Playgroud)\n is_transaction\n----------------\n f\n(1 row)\nRun Code Online (Sandbox Code Playgroud)\n is_transaction\n----------------\n f\n(1 row)\nRun Code Online (Sandbox Code Playgroud)\n is_transaction\n----------------\n f\n(1 row)\nRun Code Online (Sandbox Code Playgroud)\nBEGIN TRANSACTION; -- Making it explicitly READ WRITE won\'t make a difference.\n\nSELECT pg_current_xact_id_if_assigned() IS NOT NULL AS is_transaction;\nRun Code Online (Sandbox Code Playgroud)\n is_transaction\n----------------\n t\n(1 row)\nRun Code Online (Sandbox Code Playgroud)\n你有它。
\n如果您在事务之外运行该CREATE TEMPORARY TABLE \xe2\x80\xa6 ON COMMIT DROP语句,则该语句将在执行每个变异语句(在自动提交模式下)的隐式事务结束时消失。
编辑1:请注意,您不能将此逻辑包装到函数或过程中,因为函数/过程调用语句将包装在隐式事务中,因此您的am_i_inside_a_transaction()函数将始终返回TRUE.
编辑2:我想澄清的是,除了我的答案的信息价值之外,我仍然相信@Gajus他自己的答案中的比较时间戳方法优于该pg_current_xact_id_if_assigned()方法。他的方法可以通过使用transaction_timestamp()而不是变得更加明确now():
is_transaction\n----------------\n f\n(1 row)\nRun Code Online (Sandbox Code Playgroud)\nCREATE TEMPORARY TABLE a (b int) ON COMMIT DROP;\n\nSELECT pg_current_xact_id_if_assigned() IS NOT NULL AS is_transaction;\nRun Code Online (Sandbox Code Playgroud)\n is_transaction\n----------------\n t\n(1 row)\nRun Code Online (Sandbox Code Playgroud)\nCREATE FUNCTION in_transaction() RETURNS boolean\nLANGUAGE SQL\nRETURN transaction_timestamp() != statement_timestamp()\n;\nRun Code Online (Sandbox Code Playgroud)\n in_transaction\n----------------\n t\n(1 row)\nRun Code Online (Sandbox Code Playgroud)\n不过,这里也需要注意,因为statement_timestamp()\xe2\x80\x9c 是从客户端 \xe2\x80\x9d 接收最新命令消息的时间。这意味着如果您要将上述函数调用嵌套在另一个函数中,该函数将始终返回FALSE.
| 归档时间: |
|
| 查看次数: |
6125 次 |
| 最近记录: |