Postgresql 中文操作指南
36.2. Managing Database Connections #
本节介绍如何打开、关闭和切换数据库连接。
36.2.1. Connecting to the Database Server #
可以使用以下语句连接到数据库:
EXEC SQL CONNECT TO target [AS connection-name] [USER user-name];
target 可以通过以下方式指定:
连接目标 DEFAULT 在默认用户名下启动到默认数据库的连接。在这种情况下,不能指定单独的用户名或连接名称。
如果直接指定连接目标(即,不是作为字符串文字或变量引用),则目标组件将通过常规 SQL 解析;这意味着,例如,hostname 必须看起来像一个或多个由点分隔的 SQL 标识符,并且除非使用双引号,否则这些标识符将折叠大小写。任何 options 的值必须是 SQL 标识符、整数或变量引用。当然,通过双引号,你可以将几乎任何内容放入 SQL 标识符中。实际上,可能更不容易出错,可以使用(单引号)字符串文字或变量引用,而不是直接写入连接目标。
还可以使用不同的方式指定用户名:
如上所述,参数 username 和 password 可以是 SQL 标识符、SQL 字符串文本或对字符变量的引用。
如果连接目标包括任何 options ,则那些目标由用与号分隔的 keyword=value 规范组成( & )。可允许的关键字与 libpq 识别的关键词相同(参见 Section 34.1.2 )。在任何 keyword 或 value 之前会忽略空格,但在一个 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; */
最后一个示例使用了上面提到的字符变量引用的特性。在后面章节中,您将看到当用冒号为 C 变量添加前缀时,如何在 SQL 语句中使用它们。
需要注意的是,SQL 标准未指定连接目标的格式。因此,如果您想开发可移植应用程序,则可能需要使用基于上述最后一个示例的内容,将连接目标字符串封装到某个地方。
如果不受信用户可以访问尚未采用 secure schema usage pattern 的数据库,从 search_path 中移除可公开写的模式来开始每个会话。例如,将 options=-c search_path= 添加到 options 中,或在连接后发出 EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); 。此注意事项并非只针对 ECPG;它适用于执行任意 SQL 命令的每个界面。
36.2.2. Choosing a Connection #
嵌入式 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
36.2.3. Closing a Connection #
要关闭连接,请使用以下语句:
EXEC SQL DISCONNECT [connection];
connection 可通过以下方式指定:
如果没有指定连接名称,则当前连接将关闭。
一个好的开发实践是应用程序始终显式断开与它已打开的每个连接。