【问题标题】:Identifying a connection ID in Postgres在 Postgres 中识别连接 ID
【发布时间】:2011-02-21 20:27:01
【问题描述】:

我有一个 Postgres 数据库 (9),我正在为其编写触发器。我希望触发器设置修改时间和记录的用户 ID。在 Firebird 中,您有一个可以在触发器中使用的 CONNECTIONID,因此您可以在连接到数据库时向表中添加一个值(这是一个桌面应用程序,因此连接在应用程序的整个生命周期内都是持久的),例如这个:

用户名 |连接 ID --------------------- 第544章3775

然后在触发器中查找connectionid 3775属于userid 544,并将544作为修改记录的用户。

我可以在 Postgres 中使用类似的东西吗?

【问题讨论】:

    标签: delphi postgresql database-connection


    【解决方案1】:

    您可以使用进程 ID。它可以通过以下方式检索:

    pg_backend_pid()
    

    使用这个 pid,您还可以使用表 pg_stat_activity 来获取有关当前后端的更多信息,尽管您已经应该知道一切,因为您正在使用这个后端。

    或者更好。只需创建一个序列,并为每个连接从中检索一个值:

    CREATE SEQUENCE 'connectionids';
    

    然后:

    SELECT next_val('connectionids');
    

    在每个连接中,检索一个连接唯一ID。

    【讨论】:

    • 谢谢丹尼尔,但我检查了这一点,并且在连接到数据库的生命周期内这会发生变化。我需要不变的东西。
    • 这不会改变!如果是这样,您实际上并没有使用相同的连接。检查您是否有连接池,并且不小心从中检索连接!
    • 谢谢丹尼尔,我使用 EMS Studio for Postgres,我在那里检查了这个,每次我打开一个新的查询窗口我都会得到一个新的结果。我假设它每笔交易都会改变。也许 EMS 会为每个查询窗口打开一个新连接?我将使用我控制的连接构建一个测试应用程序,并在那里检查它并让你知道它是否有效。
    • 你的序列想法行不通,我需要像每个连接都可以读取的 pid 之类的东西。我可以创建一个序列,但是如何在触发器中关联它。希望 PID 交易有效,我会尽快通知您。
    • pg_backend_pid() (不确定pg_get_pid() 来自哪里?)确实可以识别连接。每个查询窗口使用一个连接听起来很合理——mssql 企业管理器、toad 等以这种方式工作(默认情况下)
    【解决方案2】:

    一种方法是使用custom_variable_classes 配置选项。它似乎被设计为允许配置附加模块,但也可用于在当前数据库会话中存储任意值。

    类似于以下内容的内容需要添加到postgresql.conf

    custom_variable_classes = 'local'
    

    当您第一次连接到数据库时,您可以在自定义类中存储您需要的任何信息,如下所示:

    SET local.userid = 'foobar';
    

    稍后您可以使用current_setting() 函数检索此值:

    SELECT current_setting('local.userid');
    

    向日志表添加条目可能如下所示:

    INSERT INTO audit_log VALUES (now(), current_setting('local.userid'), ...)
    

    【讨论】:

    【解决方案3】:

    虽然它可能适用于您的桌面用例,但请注意进程 ID 编号会翻转(32768 是常见的上限),因此将它们用作唯一键来识别用户可能会遇到问题。如果您最终在跟踪用户-> 进程映射的表中得到上一个会话的剩余数据,那么一旦它翻转,它可能会与分配了相同进程 ID 的新连接发生冲突。您的应用只需确保积极清除旧的映射条目就足够了,可能在启动时考虑到您描述其操作的方式。

    为了避免这个问题,您需要创建一个包含额外信息的连接密钥,例如会话何时开始:

    SELECT procpid,backend_start FROM pg_stat_activity WHERE procpid=pg_backend_pid();
    

    这必须遍历所有活动的连接来计算,所以它确实增加了一些开销。从 PostgreSQL 8.4 开始可以更有效地执行它:

    SELECT procpid,backend_start FROM pg_stat_get_activity(pg_backend_pid());
    

    但这只有在您同时有大量连接处于活动状态时才真正重要。

    【讨论】:

      【解决方案4】:

      如果您需要数据库用户,请使用 current_user(通过阅读您的问题,我不确定这是否是您想要的)。

      【讨论】:

      • 感谢您的建议,但我对所有连接都使用同一个用户,并且在数据库中有一个内部定义的用户表,所以这不起作用。
      猜你喜欢
      • 1970-01-01
      • 2020-03-27
      • 1970-01-01
      • 2014-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多