2024年9月26日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不支持的版本:11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3

34.2. 管理数据库连接 #

本节介绍如何打开、关闭和切换数据库连接。

34.2.1. 连接到数据库服务器 #

使用以下语句连接到数据库

EXEC SQL CONNECT TO target [AS connection-name] [USER user-name];

目标 可以通过以下方式指定

  • 数据库名[@主机名][:端口]
  • tcp:postgresql://主机名[:端口][/数据库名][?选项]
  • unix:postgresql://127.0.0.1[:端口][/数据库名][?选项]
  • 包含上述形式之一的 SQL 字符串文字
  • 对包含上述形式之一的字符变量的引用(参见示例)
  • 默认

连接目标 默认 初始化与默认用户名下的默认数据库的连接。在这种情况下,无法单独指定用户名或连接名。

如果直接指定连接目标(即,不作为字符串文字或变量引用),则目标的组件将通过正常的 SQL 解析传递;这意味着,例如,主机名 必须看起来像一个或多个用点分隔的 SQL 标识符,并且这些标识符将被折叠成小写,除非用双引号括起来。任何 选项 的值必须是 SQL 标识符、整数或变量引用。当然,您可以通过双引号括起来将几乎任何内容放入 SQL 标识符中。在实践中,使用(单引号括起来的)字符串文字或变量引用可能比直接编写连接目标更不容易出错。

还有不同的方法来指定用户名

  • 用户名
  • 用户名/密码
  • 用户名 IDENTIFIED BY 密码
  • 用户名 USING 密码

与上面一样,参数 用户名密码 可以是 SQL 标识符、SQL 字符串文字或对字符变量的引用。

如果连接目标包含任何 选项,则这些选项由 关键字= 规范组成,这些规范由与号 (&) 分隔。允许的关键字与 libpq 识别的关键字相同(参见 第 32.1.2 节)。在任何 关键字 之前都会忽略空格,但不会忽略在其中或之后的空间。请注意,无法在 中写入 &

请注意,在指定套接字连接(使用 unix: 前缀)时,主机名必须正好是 localhost。要选择非默认套接字目录,请将目录的路径名写入 host 选项的值,该选项位于目标的 选项 部分。

连接名 用于在一个程序中处理多个连接。如果程序只使用一个连接,则可以省略它。最近打开的连接将成为当前连接,默认情况下,当要执行 SQL 语句时会使用它(参见本章后面的内容)。

以下是一些 CONNECT 语句的示例

EXEC SQL CONNECT TO [email protected];

EXEC SQL CONNECT TO tcp:postgresql://sql.mydomain.com/mydb AS myconnection USER john;

EXEC SQL BEGIN DECLARE SECTION;
const char *target = "[email protected]";
const char *user = "john";
const char *passwd = "secret";
EXEC SQL END DECLARE SECTION;
 ...
EXEC SQL CONNECT TO :target USER :user USING :passwd;
/* or EXEC SQL CONNECT TO :target USER :user/:passwd; */

最后一个示例使用了上面提到的字符变量引用功能。在后面的部分中,您将看到如何在使用冒号作为前缀时,在 SQL 语句中使用 C 变量。

请注意,连接目标的格式未在 SQL 标准中指定。因此,如果您想开发可移植应用程序,您可能希望使用类似于上面最后一个示例的内容来将连接目标字符串封装在某个地方。

如果不受信任的用户可以访问尚未采用 安全模式使用模式 的数据库,请在每个会话开始时从 search_path 中删除可公开写入的模式。例如,将 options=-c search_path= 添加到 选项,或者在连接后发出 EXEC SQL SELECT pg_catalog.set_config('search_path', '', false);。此注意事项不是特定于 ECPG 的;它适用于执行任意 SQL 命令的每个接口。

34.2.2. 选择连接 #

嵌入式 SQL 程序中的 SQL 语句默认情况下在当前连接上执行,即最近打开的连接。如果应用程序需要管理多个连接,则有三种方法可以处理此问题。

第一个选项是为每个 SQL 语句显式选择一个连接,例如

EXEC SQL AT connection-name SELECT ...;

此选项特别适用于应用程序需要以混合顺序使用多个连接的情况。

如果您的应用程序使用多个执行线程,它们不能同时共享一个连接。您必须要么显式控制对连接的访问(使用互斥锁),要么为每个线程使用一个连接。

第二个选项是执行一个语句来切换当前连接。该语句是

EXEC SQL SET CONNECTION connection-name;

此选项特别适合在同一个连接上执行多个语句的情况。

以下是一个管理多个数据库连接的示例程序

#include <stdio.h>

EXEC SQL BEGIN DECLARE SECTION;
    char dbname[1024];
EXEC SQL END DECLARE SECTION;

int
main()
{
    EXEC SQL CONNECT TO testdb1 AS con1 USER testuser;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
    EXEC SQL CONNECT TO testdb2 AS con2 USER testuser;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
    EXEC SQL CONNECT TO testdb3 AS con3 USER testuser;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;

    /* This query would be executed in the last opened database "testdb3". */
    EXEC SQL SELECT current_database() INTO :dbname;
    printf("current=%s (should be testdb3)\n", dbname);

    /* Using "AT" to run a query in "testdb2" */
    EXEC SQL AT con2 SELECT current_database() INTO :dbname;
    printf("current=%s (should be testdb2)\n", dbname);

    /* Switch the current connection to "testdb1". */
    EXEC SQL SET CONNECTION con1;

    EXEC SQL SELECT current_database() INTO :dbname;
    printf("current=%s (should be testdb1)\n", dbname);

    EXEC SQL DISCONNECT ALL;
    return 0;
}

此示例将生成以下输出

current=testdb3 (should be testdb3)
current=testdb2 (should be testdb2)
current=testdb1 (should be testdb1)

第三个选项是声明一个与连接链接的 SQL 标识符,例如

EXEC SQL AT connection-name DECLARE statement-name STATEMENT;
EXEC SQL PREPARE statement-name FROM :dyn-string;

将 SQL 标识符链接到连接后,您可以在没有 AT 子句的情况下执行动态 SQL。请注意,此选项的行为类似于预处理器指令,因此链接仅在文件中启用。

以下是一个使用此选项的示例程序

#include <stdio.h>

EXEC SQL BEGIN DECLARE SECTION;
char dbname[128];
char *dyn_sql = "SELECT current_database()";
EXEC SQL END DECLARE SECTION;

int main(){
  EXEC SQL CONNECT TO postgres AS con1;
  EXEC SQL CONNECT TO testdb AS con2;
  EXEC SQL AT con1 DECLARE stmt STATEMENT;
  EXEC SQL PREPARE stmt FROM :dyn_sql;
  EXEC SQL EXECUTE stmt INTO :dbname;
  printf("%s\n", dbname);

  EXEC SQL DISCONNECT ALL;
  return 0;
}

此示例将生成以下输出,即使默认连接是 testdb

postgres

34.2.3. 关闭连接 #

要关闭连接,请使用以下语句

EXEC SQL DISCONNECT [connection];

连接 可以通过以下方式指定

  • 连接名
  • 当前
  • 全部

如果未指定连接名,则将关闭当前连接。

应用程序始终显式断开与它打开的每个连接的连接是一种良好的风格。

提交更正

如果您在文档中看到任何不正确的内容、与您对特定功能的体验不符或需要进一步澄清,请使用 此表格 报告文档问题。