PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

34.2. 管理数据库连接 #

34.2.1. 连接到数据库服务器
34.2.2. 选择当前连接
34.2.3. 关闭数据库连接

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

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

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

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

target 可以按以下方式指定:

  • dbname[@hostname][:port]
  • tcp:postgresql://hostname[:port][/dbname][?options]
  • unix:postgresql://localhost[:port][/dbname][?options]
  • 一个包含上述形式之一的 SQL 字符串字面值
  • 对包含上述形式之一的字符变量的引用(见示例)
  • DEFAULT

连接目标 DEFAULT 会以默认用户名 发起到默认数据库的连接。在这种情况下 不能单独指定用户名或连接名。

如果你直接指定连接目标(即不以字符串字面值或变量引用的形式), 那么目标的各个组成部分会经过普通的 SQL 解析; 这意味着例如 hostname 必须形如一个或多个以点分隔的 SQL 标识符, 并且除非被双引号括起,这些标识符会被折叠为小写。 任何 options 的值必须是 SQL 标识符、 整数或变量引用。当然,把几乎任何内容放进双引号括起的 SQL 标识符都是可以的。在实践中, 使用(单引号括起的)字符串字面值或变量引用 可能比直接书写连接目标更不容易出错。

还有几种不同的方式来指定用户名:

  • username
  • username/password
  • username IDENTIFIED BY password
  • username USING password

与上文一样,参数 username 和 password 可以是 SQL 标识符、 SQL 字符串字面值或对字符变量的引用。

如果连接目标中包含任何 options, 它们由以和号(&)分隔的 keyword=value 规范构成。允许的关键字与 libpq 识别的关键字相同 (见 Section 32.1.2)。 在任何 keyword 或 value 之前的空格会被忽略, 但其内部或之后的空格不会。注意, 没有办法在 value 内部书写 &。

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

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

下面是一些 CONNECT 语句的示例:

EXEC SQL CONNECT TO mydb@sql.mydomain.com;

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

EXEC SQL BEGIN DECLARE SECTION;
const char *target = "mydb@sql.mydomain.com";
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 中加入 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)
", dbname);

    /* Using "AT" to run a query in "testdb2" */
    EXEC SQL AT con2 SELECT current_database() INTO :dbname;
    printf("current=%s (should be testdb2)
", 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)
", 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 标识符关联到某个连接, 执行动态 SQL 时就无需 AT 子句。注意, 该选项的行为类似于预处理器指令, 因此该关联只在当前文件中生效。

下面是一个使用该选项的示例程序:

#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
", dbname);

  EXEC SQL DISCONNECT ALL;
  return 0;
}

即使默认连接是 testdb,这个例子也会产生如下输出:

postgres

34.2.3. 关闭数据库连接 #

要关闭一个连接,使用以下语句:

EXEC SQL DISCONNECT [connection];

connection 可以按以下方式指定:

  • connection-name
  • CURRENT
  • ALL

如果没有指定连接名,则关闭当前连接。

应用对它打开的每一个连接都显式断开是一种良好的风格。