企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 33.2\. 管理数据库连接 本节描述了如何打开,关闭,以及切换数据库连接。 ## 33.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://``_hostname_`[:`_port_`][/`_dbname_`][?`_options_`] * 一个包含上面形式的SQL字串文本 * 一个对包含上面的形式之一的字符串变量的引用 * `DEFAULT` 如果你用文本声明连接目标(也就是说,不是通过一个变量引用), 而且你也不引用这个数值,那么使用普通SQL的大小写无关的规则。 这种情况下,你也可以根据需要独立地对参数使用双引号包围。 实际上,可能用一个(单引号包围)的 字串文本或者变量引用作为连接目标可能更结实一些。 连接目标`DEFAULT`发起一个用缺省用户名对缺省数据库地连接。 这个时候不应该声明用户名或连接名。 声明用户名的方法也有几种不同方式: * `_username_` * `_username_`/`_password_` * `_username_` IDENTIFIED BY `_password_` * `_username_` USING `_password_` 正如上面的一样,参数用户名和密码可以是一个SQL标识, 一个字符变量,或者一个字符串。 `_连接名_`用于处理一个程序里的多个连接。 如果一个程序只使用一个连接,则可以省略它。 最近打开的连接成为当前连接, 在准备执行SQL语句的时候,缺省时会使用这个连接(参阅本章稍后部分)。 这里是一些`CONNECT`语句的例子: ``` EXEC SQL CONNECT TO mydb@sql.mydomain.com; EXEC SQL CONNECT TO unix: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标准里说明。所以, 如果你想开发可以移植的应用, 你可能会想使用类似上面的最后一个例子这样的方法来把连接目标字串封装在某处。 ## 33.2.2\. 选择一个连接 在当前连接中缺省执行嵌入SQL程序的SQL语句,也就是说,最近打开的。 如果应用需要管理多个连接,那么有两种处理方法。 第一个选项是为每个SQL语句明确选择一个连接,比如: ``` EXEC SQL AT _connection-name_ SELECT ...; ``` 如果在混合顺序中应用程序需要使用若干个连接时,这个选项特别适合。 如果你的应用程序使用多个执行线程,他们不能同时共享连接。 你要么明确控制访问连接(使用互斥锁)或者为每个线程使用一个连接。 如果每个线程使用自己的连接,你将需要使用AT子句指定线程将使用哪个连接。 第二个选项是执行语句切换当前连接。语句是: ``` 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 CONNECT TO testdb2 AS con2 USER testuser; EXEC SQL CONNECT TO testdb3 AS con3 USER testuser; /*在最后打开的数据库"testdb3"中执行该查询*/ EXEC SQL SELECT current_database() INTO :dbname; printf("current=%s (should be testdb3)\n", dbname); /*在"testdb2"中使用"AT"运行查询*/ EXEC SQL AT con2 SELECT current_database() INTO :dbname; printf("current=%s (should be testdb2)\n", dbname); /*切换当前连接到"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) ``` ## 33.2.3\. 关闭一个连接 使用下面的语句关闭连接: ``` EXEC SQL DISCONNECT [`_connection_`]; ``` 通过下面的方法声明`_连接_`: * `_连接名_` * `缺省` * `当前` * `所有` 如果没有声明连接名,那么关闭当前连接。 应用保持明确关闭每次打开的连接是一个很好的习惯。