## 36.2.管理数据库连接 [36.2.1. 连接到数据库服务器](ecpg-connect.html#ECPG-CONNECTING) [36.2.2. 选择连接](ecpg-connect.html#ECPG-SET-CONNECTION) [36.2.3. 关闭连接](ecpg-connect.html#ECPG-DISCONNECT) 本节介绍如何打开、关闭和切换数据库连接。 ### 36.2.1.连接到数据库服务器 可以使用以下语句连接到数据库: ``` EXEC SQL CONNECT TO target [AS connection-name] [USER user-name]; ``` 这个*`目标`*可通过以下方式指定: - `*`库名`*[@*`主机名`*][:*`港口城市`*]` - `tcp:postgresql://*`主机名`*[:*`港口城市`*][/*`库名`*][?*`选项`*]` - `unix:postgresql://localhost[:*`港口城市`*][/*`库名`*][?*`选项`*]` - 包含上述形式之一的SQL字符串文字 - 对包含上述形式之一的字符变量的引用(参见示例) - `违约` 连接目标`违约`以默认用户名启动到默认数据库的连接。在这种情况下,不能指定单独的用户名或连接名。 如果直接指定连接目标(即,不作为字符串文字或变量引用),则目标的组件将通过正常的SQL解析传递;这意味着,例如*`主机名`*必须看起来像一个或多个由点分隔的SQL标识符,这些标识符将被大小写折叠,除非双引号。任何价值观*`选项`*必须是SQL标识符、整数或变量引用。当然,您可以通过双引号将几乎任何内容放入SQL标识符中。实际上,与直接编写连接目标相比,使用(单引号)字符串文字或变量引用可能更不容易出错。 指定用户名也有不同的方法: - `*`用户名`*` - `*`用户名`*/*`暗语`*` - `*`用户名`*识别人*`暗语`*` - `*`用户名`*使用*`暗语`*` 如上所述,参数*`用户名`*和*`暗语`*可以是SQL标识符、SQL字符串文字或对字符变量的引用。 如果连接目标包括*`选项`*,包括`*`关键词`*=*`价值`*`用符号隔开的规格(`&`).允许的关键字与libpq识别的关键字相同(参见[第34.1.2节](libpq-connect.html#LIBPQ-PARAMKEYWORDS))。在任何*`关键词`*或*`价值`*,但不是在一年之内或之后。注意,没有写的方法`&`在一分钟之内*`价值`*. 请注意,在指定套接字连接时(使用`unix:`前缀),主机名必须完全相同`本地服务器`。要选择非默认套接字目录,请将该目录的路径名写入`主办`中的选项*`选项`*部分目标。 这个*`连接名`*用于在一个程序中处理多个连接。如果一个程序只使用一个连接,则可以省略它。最近打开的连接将成为当前连接,在执行SQL语句时默认使用该连接(请参阅本章下文)。 下面是一些例子`连接`声明: ``` 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标准中没有指定连接目标的格式。因此,如果你想开发可移植的应用程序,你可能想使用基于上一个例子的东西来封装连接目标字符串。 如果不受信任的用户可以访问未采用[安全模式使用模式](ddl-schemas.html#DDL-SCHEMAS-PATTERNS),通过从中删除可公开写入的架构开始每个会话`搜索路径`.例如,添加`选项=-c搜索路径=`到`*`选项`*`,或问题`EXEC SQL选择pg_目录。设置配置('search_path','',false);`连接后。这种考虑并不是ECPG特有的;它适用于执行任意SQL命令的每个接口。 ### 36.2.2.选择连接 默认情况下,嵌入式SQL程序中的SQL语句会在当前连接(即最近打开的连接)上执行。如果一个应用程序需要管理多个连接,那么有三种方法来处理。 第一个选项是为每个SQL语句显式选择一个连接,例如: ``` EXEC SQL AT connection-name SELECT ...; ``` 如果应用程序需要以混合顺序使用多个连接,此选项尤其适用。 如果应用程序使用多个执行线程,则它们不能同时共享一个连接。您必须显式控制对连接的访问(使用互斥)或为每个线程使用连接。 第二个选项是执行一条语句来切换当前连接。该声明是: ``` EXEC SQL SET CONNECTION connection-name; ``` 如果要在同一个连接上执行多个语句,则此选项特别方便。 下面是一个管理多个数据库连接的示例程序: ``` #include 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 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.关闭连接 要关闭连接,请使用以下语句: ``` EXEC SQL DISCONNECT [connection]; ``` 这个*`联系`*可通过以下方式指定: - `*`连接名`*` - `违约` - `现在的` - `全部的` 如果未指定连接名称,则关闭当前连接。 应用程序总是显式地断开与它打开的每个连接的连接,这是一种很好的方式。