警告
本节包含自动从 C++ 转换为 Python 的代码片段,可能存在错误。
SQL 数据库驱动#
如何配置和安装 Qt SQL 驱动以支持数据库。
Qt SQL 模块使用驱动插件与不同的数据库 API 进行通信。由于 Qt 的 SQL 模块 API 是数据库无关的,所有特定于数据库的代码都包含在这些驱动器中。Qt 提供了一些驱动程序,还可以添加其他驱动程序。驱动器源代码提供,并且可以作为 编写自己的驱动 的模板。
支持的数据库#
下表列出了 Qt 包含的驱动程序
SQLite 是性能和支持最佳的进程内数据库系统,在所有平台上均有良好的测试。Oracle 通过 OCI、PostgreSQL 以及 MySQL 通过 ODBC 或本地驱动在 Windows 和 Linux 上进行了充分的测试。对其他系统的支持程度取决于客户端库的可用性和质量。
注意
要构建驱动插件,您需要为您的数据库管理系统 (DBMS) 获取相应的客户端库。这提供了对 DBMS 提供的 API 的访问权限,并且通常与它一起提供。大多数安装程序也允许您安装“开发库”,这些就是您所需要的。这些库负责与 DBMS 进行低级通信。确保安装与您的 Qt 架构(32 位或 64 位)正确的数据库库。
注意
当在开源条款下使用 Qt 但使用专有数据库时,请检查客户端库的许可证兼容性是否符合 LGPL。
构建驱动#
编译 Qt 时使用特定驱动#
Qt 的 configure
脚本会尝试自动检测您机器上的可用客户端库。运行 configure -help
来查看可以构建的驱动。您应该得到以下类似的输出
[...] Database options: -sql-<driver> ........ Enable SQL <driver> plugin. Supported drivers: db2 ibase mysql oci odbc psql sqlite [all auto] -sqlite .............. Select used sqlite [system/qt] [...]
如果所需的库和包含文件不在标准路径中,configure
脚本无法检测到它们,因此可能需要通过特定的驱动程序包含和库路径变量或 CMAKE_INCLUDE_PATH
和 `CMAKE_LIBRARY_PATH
` 来指定这些路径。例如,如果您的 MySQL 文件安装在 Windows 的 C:\mysql-connector-c-6.1.11-winx64
,请在 configure
行的双短横线部分传递以下参数
C:\Qt\6.0.0\Src\configure.bat -sql-mysql -- -DMySQL_INCLUDE_DIR="C:\mysql-8.0.22-winx64\include" -DMySQL_LIBRARY="C:\mysql-8.0.22-winx64\lib\libmysql.lib" Configure summary: ... Qt Sql Drivers: DB2 (IBM) .............................. no InterBase .............................. no Mimer SQL .............................. yes MySql .................................. yes OCI (Oracle) ........................... no ODBC ................................... yes PostgreSQL ............................. no SQLite ................................. yes Using system provided SQLite ......... no ...
按照上述方式配置驱动程序时,CMake 会跳过任何依赖性检查,并直接使用提供的路径。如果该软件包提供了应不被构建过程识别的自有一套系统库,这特别有用。
在某些情况下,使用 CMAKE_INCLUDE_PATH
和 CMAKE_LIBRARY_PATH
变量来查找所需的库更方便。当需要为提供的目标库设置属性(例如,对于 PostgreSQL 和 SQLite 这是必需的)时,您应该优先使用此方法。例如,您可以像下面这样做来查找 MySQL
C:\Qt\6.0.0\Src\configure.bat -sql-mysql -- -DCMAKE_INCLUDE_PATH="C:\mysql-8.0.22-winx64\include" -DCMAKE_LIBRARY_PATH="C:\mysql-8.0.22-winx64\lib" Configure summary: ... Qt Sql Drivers: DB2 (IBM) .............................. no InterBase .............................. no Mimer SQL .............................. yes MySql .................................. yes OCI (Oracle) ........................... no ODBC ................................... yes PostgreSQL ............................. no SQLite ................................. yes Using system provided SQLite ......... no ...
以下是每个驱动程序的具体细节。
注意
如果出现问题,并且您想让 CMake 重新检查您的可用驱动程序,可能需要从构建目录中删除 CMakeCache.txt。
仅编译特定的 SQL 驱动器#
一个典型的 qt-cmake
运行(在这种情况下用于配置 MySQL)如下所示
C:\Qt\6.0.0\mingw81_64\bin\qt-cmake -G Ninja C:\Qt\6.0.0\Src\qtbase\src\plugins\sqldrivers -DMySQL_INCLUDE_DIR="C:\mysql-8.0.22-winx64\include" -DMySQL_LIBRARY="C:\mysql-8.0.22-winx64\lib\libmysql.lib" -DCMAKE_INSTALL_PREFIX="C:\Qt\6.0.0\mingw81_64" Configure summary: Qt Sql Drivers: DB2 (IBM) .............................. no InterBase .............................. no Mimer SQL .............................. yes MySql .................................. yes OCI (Oracle) ........................... no ODBC ................................... yes PostgreSQL ............................. no SQLite ................................. yes Using system provided SQLite ......... no -- Configuring done -- Generating done -- Build files have been written to: C:/build-qt6-sqldrivers
注意
如 使用特定驱动编译 Qt 中所述,如果找不到驱动程序或驱动程序未启用,可以通过删除 CMakeCache.txt 从头开始。
由于处理外部依赖的实际问题,只将 SQLite 插件包含在 Qt 的二进制构建中。Windows 版本的 Qt 二进制构建还包括 ODBC 插件。为了在不重新构建所有 Qt 的情况下将额外的驱动程序添加到 Qt 安装中,可以在完整的 Qt 构建目录外配置和构建 `qtbase/src/plugins/sqldrivers
` 目录。请注意,无法分别配置每个驱动程序,只能一次配置所有驱动程序。尽管如此,驱动程序可以分别构建。
注意
如果想在构建完成后安装插件,您需要指定 CMAKE_INSTALL_PREFIX
。
驱动程序特定#
针对 MySQL 或 MariaDB 5.6 及以上版本的 QMYSQL#
MariaDB 是 MySQL 的一个分支,目的是在 GNU 通用公共许可证下保持免费和开源软件的状态。MariaDB 旨在保持与 MySQL 的高度兼容性,确保可以通过库的二进制兼容性和与 MySQL API 和命令的精确匹配来实现直接替代能力。因此,MySQL 和 MariaDB 的插件合并成了一个 Qt 插件。
QMYSQL 存储过程支持#
MySQL 在 SQL 级别支持存储过程,但没有 API 来控制 IN、OUT 和 INOUT 参数。因此,参数需要通过 SQL 命令来设置和读取,而不是使用 bindValue
。
示例存储过程
create procedure qtestproc (OUT param1 INT, OUT param2 INT) BEGIN set param1 = 42; set param2 = 43; END
访问 OUT 值的源代码
q = QSqlQuery() q.exec("call qtestproc (@outval1, @outval2)") q.exec("select @outval1, @outval2") if q.next(): print(q.value(0), q.value(1) # outputs "42" and "43")
注意
@outval1
和 @outval2
是当前连接中的局部变量,不会被来自其他主机或连接发送的查询所影响。
嵌入式 MySQL 服务器#
MySQL 嵌入式服务器是正常客户端库的替代品。使用嵌入式 MySQL 服务器时,无需 MySQL 服务器即可使用 MySQL 功能。
要使用嵌入式 MySQL 服务器,只需将 Qt 插件链接到 libmysqld
而不是 libmysqlclient
。这可以通过在配置命令行中添加 -DMySQL_LIBRARY=<path/to/mysqld/>libmysqld.<so|lib|dylib>
来实现。
有关 MySQL 嵌入式服务器的更多信息,请参阅 MySQL 文档中的“libmysqld,嵌入式 MySQL 服务器库”章节。
连接选项#
Qt MySQL/MariaDB 插件遵循以下连接选项
属性
可能的值
CLIENT_COMPRESS
如果设置,则在成功认证后切换到压缩协议
CLIENT_FOUND_ROWS
如果设置,发送找到的行而不是受影响的行
CLIENT_IGNORE_SPACE
如果设置,忽略 `(` 前面的空格
CLIENT_NO_SCHEMA
如果设置,不允许使用数据库.表.列
CLIENT_INTERACTIVE
如果设置,客户端被视为交互式
MYSQL_OPT_PROTOCOL
显式指定要使用的协议:MYSQL_PROTOCOL_TCP: 使用 tcp 连接(通过 setHostname() 指定的 ip/hostname) MYSQL_PROTOCOL_SOCKET: 通过在 UNIX_SOCKET 中指定的套接字进行连接 MYSQL_PROTOCOL_PIPE: 通过在 UNIX_SOCKET 中指定的命名管道进行连接 MYSQL_PROTOCOL_MEMORY: 通过在 MYSQL_SHARED_MEMORY_BASE_NAME 中指定的共享内存进行连接
UNIX_SOCKET
指定要使用的套接字或命名管道,即使在 Windows 上也可以使用
MYSQL_SHARED_MEMORY_BASE_NAME
指定要使用的共享内存段名称
MYSQL_OPT_RECONNECT
TRUE 或 1:在连接丢失后自动重新连接 FALSE 或 0:连接丢失后不自动重新连接(默认)参见 自动重新连接控制
MYSQL_OPT_CONNECT_TIMEOUT
用于连接的秒数超时
MYSQL_OPT_READ_TIMEOUT
对于从服务器读取的每个尝试的超时时长(秒)
MYSQL_OPT_WRITE_TIMEOUT
对于写入服务器的每个尝试的超时时长(秒)
MYSQL_OPT_LOCAL_INFILE
设置为 1 以启用对本地 LOAD_DATA 的支持,未设置或为 0 时禁用
MYSQL_OPT_SSL_MODE
对于连接到服务器的连接要使用的安全状态:SSL_MODE_DISABLED,SSL_MODE_PREFERRED,SSL_MODE_REQUIRED,SSL_MODE_VERIFY_CA,SSL_MODE_VERIFY_IDENTITY。
MYSQL_OPT_TLS_VERSION
客户端允许的协议列表,客户端允许的加密连接协议可以是 "TLSv1" ," TLSv1.1", "TLSv1.2" 或 "TLSv1.3",具体取决于使用的 MySQL 服务器 版本。
MYSQL_OPT_SSL_KEY / SSL_KEY (已弃用)
客户端私钥文件的路径名
MYSQL_OPT_SSL_CERT / SSL_CERT (已弃用)
客户端公钥证书文件的路径名
MYSQL_OPT_SSL_CA / SSL_CA (已弃用)
证书授权 (CA) 证书文件的路径名
MYSQL_OPT_SSL_CAPATH / SSL_CAPATH (已弃用)
包含受信任 SSL CA 证书文件的目录的路径名
MYSQL_OPT_SSL_CIPHER / SSL_CIPHER (已弃用)
SSL 加密中允许的密码列表
MYSQL_OPT_SSL_CRL
证书吊销列表文件的路名
MYSQL_OPT_SSL_CRLPATH
包含证书吊销列表文件的目录的路名
有关连接选项的更详细信息,请参阅 mysql_options() MySQL 文档。
如何在 Unix 和 macOS 上构建 QMYSQL 插件#
您需要 MySQL / MariaDB 的头文件以及共享库 libmysqlclient.<so|dylib>
/ libmariadb.<so|dylib>
。根据您的 Linux 发行版,您可能需要安装一个通常称为“mysql-devel”或“mariadb-devel”的软件包。
告诉 qt-cmake
在哪里可以找到 MySQL / MariaDB 的头文件和共享库(此处假设 MySQL / MariaDB 安装在 /usr/local
)并构建
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_source_directory>/qtbase/src/plugins/sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>/<platform> -DMySQL_INCLUDE_DIR="/usr/local/mysql/include" -DMySQL_LIBRARY="/usr/local/mysql/lib/libmysqlclient.<so|dylib>" cmake --build . cmake --install .
如何在 Windows 上构建 QMYSQL 插件#
您需要获取 MySQL 安装文件(例如,MySQL 网络安装程序 或 MariaDB C 连接器)。运行安装程序,选择自定义安装并将匹配您 Qt 安装的 MySQL C 连接器(x86 或 x64)安装。安装后,请检查所需文件是否存在
<MySQL dir>/lib/libmysql.lib
<MySQL dir>/lib/libmysql.dll
<MySQL dir>/include/mysql.h
以及对于 MariaDB
<MariaDB dir>/lib/libmariadb.lib
<MariaDB dir>/lib/libmariadb.dll
<MariaDB dir>/include/mysql.h
注意
从 MySQL 8.0.19 开始,C 连接器不再作为可单独安装的组件提供。相反,您可以通过安装完整的 MySQL Server(仅限 x64)或 MariaDB C 连接器 来获取 mysql.h
和 libmysql.*
。
按照以下步骤构建插件(这里假设 <MySQL dir>
是 C:\mysql-8.0.22-winx64
)
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DMySQL_INCLUDE_DIR="C:\mysql-8.0.22-winx64\include" -DMySQL_LIBRARY="C:\mysql-8.0.22-winx64\lib\libmysql.lib" cmake --build . cmake --install .
当您分发您的应用程序时,请记得在您的安装包中包括 libmysql.dll / libmariadb.dll。它必须放置在与应用程序可执行文件相同的文件夹中。libmysql.dll 还需要 MSVC 运行时库,这些库可以通过 vcredist.exe 安装
为 Oracle 调用接口 (OCI) 的 QOCI#
Qt OCI 插件支持根据使用的即时客户端版本连接到 Oracle 数据库。这取决于 Oracle 所指示它支持的内容。插件将自动检测数据库版本并相应地启用功能。
您在不使用 tnsnames.ora 文件的情况下连接到 Oracle 数据库。这需要将数据库 SID 作为数据库名称传递给驱动程序,并给出一个主机名。
OCI 用户身份验证#
Qt OCI 插件支持使用外部凭据(OCI_CRED_EXT)进行身份验证。通常情况下,这意味着数据库服务器将使用操作系统提供的用户身份验证而不是它自己的身份验证机制。
在通过 QSqlDatabase
打开连接时留空用户名和密码,以使用外部凭据身份验证。
OCI BLOB/LOB 支持链接到本标题 OCI BLOB/LOB 支持链接到本标题
二进制大对象(BLOBs)可以被读取和写入,但请注意,此过程可能需要大量内存。您应该使用仅向前查询来选择 LOB 字段(请参见 setForwardOnly() 方法)。
插入 BLOBs 应使用已准备好的查询,其中 BLOBs 绑定到占位符,或者使用 QSqlTableModel ,它使用已准备好的查询在内部执行此操作。
连接选项链接到本标题 连接选项链接到本标题 连接选项链接到本标题
Qt OCI 插件遵循以下连接选项
属性
可能的值
OCI_ATTR_PREFETCH_ROWS
将 OCI 属性 OCI_ATTR_PREFETCH_ROWS 设置为指定的值
OCI_ATTR_PREFETCH_MEMORY
将 OCI 属性 OCI_ATTR_PREFETCH_MEMORY 设置为指定的值
OCI_AUTH_MODE
OCI_SYSDBA:验证SYSDBA访问 OCI_SYSOPER:验证SYSOPER访问 OCI_DEFAULT:使用常规访问验证 请参见 OCISessionBegin 了解有关访问模式的更多信息
如何在 Unix 和 macOS 上构建 OCI 插件链接到本标题 如何在 Unix 和 macOS 上构建 OCI 插件链接到本标题
您只需要“基本版”和“即时客户端软件包 - 开发工具包”。
构建驱动器所需的 Oracle 库文件
libclntsh.<so|dylib>
(所有版本)
告诉 qt-cmake
Oracle 头文件和共享库的位置,然后进行构建。
我们假设您已安装了 Instant Client Package SDK 的 RPM 软件包(您需要相应地调整版本号)
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_source_directory>/qtbase/src/plugins/sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>/<platform> -DOracle_INCLUDE_DIR="/usr/include/oracle/21/client64" -DOracle_LIBRARY="/usr/lib/oracle/21/client64/lib/libclntsh.<so|dylib>" cmake --build . cmake --install .
注意
如果使用 Oracle Instant Client 软件包,则在构建 OCI SQL 插件以及在运行使用 OCI SQL 插件的应用程序时,您将需要设置 LD_LIBRARY_PATH。
如何在 Windows 上构建 OCI 插件链接到本标题 如何在 Windows 上构建 OCI 插件链接到本标题
从 Oracle 客户端安装光盘的 Oracle 客户端安装程序中选择“程序员”选项通常足以构建插件。对于某些版本的 Oracle 客户端,如果可用,您可能还需要选择“调用接口(OCI)”选项。
按照以下方式构建插件(这里假设 Oracle 客户端安装在对 C:\oracle 和 SDK 是在 C:\oracle\sdk
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DOracle_INCLUDE_DIR="C:\oracle\sdk\include" -DOracle_LIBRARY="C:\oracle\oci.lib" cmake --build . cmake --install .
在运行您的应用程序时,您还需要将 oci.dll
路径添加到您的 PATH
环境变量中
set PATH=%PATH%;C:\oracle
QODBC 用于开放数据库连接 (ODBC)链接到本标题 QODBC 用于开放数据库连接 (ODBC)链接到本标题
ODBC 是一个通用接口,可以使您使用通用接口连接到多个 DBMS。QODBC 驱动程序允许您连接到 ODBC 驱动程序管理器并访问可用的数据源。请注意,您还需要为安装在系统上的 ODBC 驱动程序管理器安装和配置 ODBC 驱动程序。然后 QODBC 插件允许您在 Qt 应用程序中使用这些数据源。
注意
如果可用,应使用本地驱动程序,而不是 ODBC 驱动程序。如果没有可用的本地驱动程序,则可以使用 ODBC 支持作为兼容数据库的回退。
在 Windows 上,ODBC 驱动程序管理器应默认安装。对于 Unix 系统,有一些实现必须首先安装。请注意,您应用程序的每个最终用户都需要安装 ODBC 驱动程序管理器,否则 QODBC 插件将无法正常工作。
当连接到ODBC数据源时,应将ODBC数据源名称传递给setDatabaseName()
函数,而不是实际的数据库名称。
QODBC插件需要一个符合ODBC规范的驱动管理程序版本2.0或更高。一些ODBC驱动声称遵循2.0版本,但并不提供所有必要的功能。因此,QODBC插件会在建立连接后检查数据源是否可以使用,如果检查失败则拒绝工作。如果您不喜欢这种行为,可以删除文件qsql_odbc.cpp
中的#define ODBC_CHECK_DRIVER
行。这样做请自行承担风险!
默认情况下,Qt会指示ODBC驱动以ODBC 2.x驱动程序的行为。然而,对于一些驱动管理器/ODBC 3.x驱动组合(例如,unixODBC/MaxDB ODBC),指示ODBC驱动以2.x驱动程序的行为可能导致驱动插件出现意外行为。为了避免这个问题,请在调用open your database connection
之前,通过设置连接选项
"SQL_ATTR_ODBC_VERSION=SQL_OV_ODBC3"
来指示ODBC驱动以3.x驱动程序的行为。请注意,这将影响ODBC驱动程序行为的多方面,例如SQLSTATEs。在设置此连接选项之前,请参考您的ODBC文档以了解可预期的行为差异。
如果您发现ODBC数据源的访问速度非常慢,请确保在ODBC数据源管理器中关闭了ODBC调用跟踪。
某些驱动程序不支持可滚动光标。在这种情况下,只能成功使用setForwardOnly()
模式的查询。
ODBC存储过程支持#
对于Microsoft SQL Server,如果存储过程使用返回语句或返回多个结果集,则只能通过使用setForwardOnly()
将查询的前向模式设置为forward才能访问返回的结果集。
# STORED_PROC uses the return statement or returns multiple result sets query = QSqlQuery() query.setForwardOnly(True) query.exec("{call STORED_PROC}")
注意
存储过程的返回语句返回的值将被丢弃。
ODBC Unicode支持#
如果定义了UNICODE,QODBC插件将使用Unicode API。在基于Windows的系统上,这是默认设置。注意,ODBC驱动程序和DBMS也必须支持Unicode。
对于Oracle 9 ODBC驱动程序(Windows),如果Oracle将所有Unicode字符串转换为本地8位表示,则有必要在ODBC驱动管理程序中检查“SQL_WCHAR支持”。
连接选项#
Qt ODBC插件遵守以下连接选项:
属性
可能的值
SQL_ATTR_ACCESS_MODE
SQL_MODE_READ_ONLY:以只读模式打开数据库 SQL_MODE_READ_WRITE:以读写模式打开数据库(默认)
SQL_ATTR_LOGIN_TIMEOUT
在登录时等待数据库连接的秒数(0值将无限期等待)
SQL_ATTR_CONNECTION_TIMEOUT
等待数据库任何请求的秒数(0值将无限期等待)
SQL_ATTR_CURRENT_CATALOG
本连接使用的目录(数据库)
SQL_ATTR_METADATA_ID
SQL_TRUE:目录函数的字符串参数被视为标识符 SQL_FALSE:目录函数的字符串参数不被视为标识符
SQL_ATTR_PACKET_SIZE
指定网络数据包大小(以字节为单位)
SQL_ATTR_TRACEFILE
包含跟踪文件名称的字符串
SQL_ATTR_TRACE
SQL_OPT_TRACE_ON:启用数据库查询跟踪 SQL_OPT_TRACE_OFF:禁用数据库查询跟踪(默认)
SQL_ATTR_CONNECTION_POOLING
在环境级别启用或禁用连接池。SQL_CP_DEFAULT, SQL_CP_OFF:关闭连接池(默认) SQL_CP_ONE_PER_DRIVER:为每个驱动程序支持一个连接池 SQL_CP_ONE_PER_HENV:为每个环境支持一个连接池
SQL_ATTR_ODBC_VERSION
SQL_OV_ODBC3:驱动程序应作为 ODBC 3.x 驱动程序 SQL_OV_ODBC2:驱动程序应作为 ODBC 2.x 驱动程序(默认)
有关连接选项的更详细信息,请参阅 SQLSetConnectAttr() ODBC 文档。
如何在 Unix 和 macOS 上构建 ODBC 插件#
建议您使用 unixODBC。您可以在 http://www.unixodbc.org 上找到最新版本和 ODBC 驱动程序。您需要 unixODBC 头文件和共享库。
告诉 qt-cmake
哪里可以找到 unixODBC 头文件和共享库(这里假设 unixODBC 安装在 /usr/local/unixODBC
),然后进行构建
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_source_directory>/qtbase/src/plugins/sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>/<platform> -DODBC_INCLUDE_DIR="/usr/local/unixODBC/include" -DODBC_LIBRARY="/usr/local/unixODBC/lib/libodbc.<so|dylib>" cmake --build . cmake --install .
如何在 Windows 上构建 ODBC 插件#
ODBC 头文件和包含文件应该已经安装在正确的目录中。您只需按照以下方式构建插件
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> cmake --build . cmake --install .
QPSQL for PostgreSQL(版本 7.3 以上)#
QPSQL 驱动程序支持 PostgreSQL 服务器 7.3 及以上版本。
有关 PostgreSQL 的更多信息,请访问 https://postgresql.ac.cn 。
QPSQL Unicode 支持#
QPSQL 驱动程序会自动检测您将要连接的 PostgreSQL 数据库是否支持 Unicode。如果服务器支持,则自动使用 Unicode。请注意,驱动程序仅支持 UTF-8 编码。如果您的数据库使用任何其他编码,则必须在编译服务器时启用 Unicode 转换支持。
Unicode 支持是在 PostgreSQL 版本 7.1 中引入的,并且只有在服务器和客户端库都配置为支持多字节时才会生效。有关如何设置已启用多字节的 PostgreSQL 服务器,请参阅 PostgreSQL 管理员指南的第 5 章。
QPSQL 区分大小写#
PostgreSQL 数据库只有在创建表时引用了表名或字段名时才会尊重大小写。例如,以下 SQL 查询将仅在大写/小写敏感的情况下匹配数据库字段:
CREATE TABLE "testTable" ("id" INTEGER);
将确保可以使用相同的名称访问。如果创建表或字段时没有使用引号,则实际的表名或字段名将自动转换为小写。当使用record()
或 primaryIndex()
访问在创建时未使用引号的表或字段时,传递给函数的名称必须是小写,以确保能找到它。例如
QString tableString("testTable"); QSqlQuery q; // Create table query is not quoted, therefore it is mapped to lower case q.exec(QString("CREATE TABLE %1 (id INTEGER)").arg(tableString)); // Call toLower() on the string so that it can be matched QSqlRecord rec = database.record(tableString.toLower());
QPSQL 只查询支持#
要使用只向前查询,必须使用 9.2 或更高版本的 PostgreSQL 客户端库构建 QPSQL 插件。如果使用较旧版本构建插件,则无法使用只向前模式 - 使用 true
调用 setForwardOnly()
将没有任何效果。
警告
如果您使用 PostgreSQL 版本 9.2 或更高版本构建 QPSQL 插件,那么您必须将应用程序与 libpq 版本 9.2 或更高版本一起分发。否则,加载 QPSQL 插件将失败,显示以下消息
QSqlDatabase: QPSQL driver not loaded
QSqlDatabase: available drivers: QSQLITE QMYSQL QMARIADB QODBC QPSQL
Could not create database object
在只向前模式中导航结果时,QSqlResult
的句柄可能会更改。使用 SQL 结果的低级句柄的应用程序必须在调用QSqlResult
的任何提取函数之后获取新句柄。示例
query = QSqlQuery() v = QVariant() query.setForwardOnly(True) query.exec("SELECT * FROM table") while query.next(): # Handle changes in every iteration of the loop v = query.result().handle() if qstrcmp(v.typeName(), "PGresult*") == 0: handle = PGresult(v.data()) if handle: # Do something...
在使用 PostgreSQL 读取只向前查询的结果时,数据库连接不能用来执行其他查询。这是 libpq 库的限制。示例
value = int() query1 = QSqlQuery() query1.setForwardOnly(True) query1.exec("select * FROM table1") while query1.next(): value = query1.value(0).toInt() if value == 1: query2 = QSqlQuery() query2.exec("update table2 set col=2") # WRONG: This will discard all results of } // query1, and cause the loop to quit
如果 query1 和 query2 使用不同的数据库连接,或者我们在 while 循环后执行 query2,这个问题就不会出现。
注意
例如 tables()、primaryIndex() 等一些 QSqlDatabase
方法的实现会隐式执行 SQL 查询,因此在导航只向前查询的结果时也不可以使用这些方法。
注意
如果 QPSQL 检测到查询结果的丢失,将打印以下警告
QPSQLDriver::getResult: Query results lost - probably discarded on executing another SQL query.
连接选项#
Qt PostgreSQL 插件尊重 PostgreSQL 文档中指定的所有连接选项 connect()。
在 Unix 和 macOS 上如何构建 QPSQL 插件#
您需要安装 PostgreSQL 客户端库和头文件。
为了使 qt-cmake
能够找到 PostgreSQL 的头文件和共享库,按以下方式构建插件(假设 PostgreSQL 客户端已安装在 /usr/local/pgsql
)
mkdir build-psql-driver cd build-psql-driver qt-cmake -G Ninja <qt_source_directory>/qtbase/src/plugins/sqldrivers-DCMAKE_INSTALL_PREFIX=<qt_installation_path>/<platform> -DCMAKE_INCLUDE_PATH="/usr/local/pgsql/include" -DCMAKE_LIBRARY_PATH="/usr/local/pgsql/lib" cmake --build . cmake --install .
在 Windows 上如何构建 QPSQL 插件#
为您的编译器安装适当的 PostgreSQL 开发者库。假设 PostgreSQL 已安装在该设备中的 C:\pgsql
,请按以下方式构建插件
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DCMAKE_INCLUDE_PATH="C:\pgsql\include" -DCMAKE_LIBRARY_PATH="C:\pgsql\lib" cmake --build . cmake --install .
MinGW用户可能需要查阅以下在线文档:PostgreSQL MinGW/Native Windows。
当您分发应用程序时,务必将libpq.dll包含在安装包中。它必须放在与应用程序可执行文件相同的文件夹中。
适用于IBM DB2的QDB2(版本7.1及以上)
Qt DB2插件可以访问IBM DB2数据库。它已在IBM DB2 v7.1和7.2上进行了测试。您必须安装IBM DB2开发客户端库,其中包含编译QDB2插件所需的头文件和库文件。
QDB2驱动程序支持预编译查询、Unicode字符串的读写以及BLOB的读写。
我们建议在调用DB2中的存储过程时使用仅向前的查询(请参阅setForwardOnly()
)。
连接选项
Qt IBM DB2插件支持以下连接选项
属性
可能的值
SQL_ATTR_ACCESS_MODE
SQL_MODE_READ_ONLY:以只读模式打开数据库 SQL_MODE_READ_WRITE:以读写模式打开数据库(默认)
SQL_ATTR_LOGIN_TIMEOUT
在登录期间等待数据库连接的秒数(最大:32767,0值将无限期等待)
如何在不限系统和macOS上构建QDB2插件
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_source_directory>/qtbase/src/plugins/sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>/<platform> -DDB2_INCLUDE_DIR="/usr/local/db2/include" -DDB2_LIBRARY="/usr/local/db2/lib/libdb2.<so|dylib>" cmake --build . cmake --install .
如何在Windows上构建QDB2插件
DB2头文件和包含文件应该已经安装在正确的目录中。您只需按以下方式构建插件
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DDB2_INCLUDE_DIR="C:\db2\include" -DDB2_LIBRARY="C:\db2\lib\db2.lib" cmake --build . cmake --install .
适用于SQLite的QSQLITE(版本3及以上)
Qt SQLite插件使得访问SQLite数据库成为可能。SQLite是一个进程内数据库,这意味着不需要数据库服务器。SQLite在单个文件上运行,在打开连接时必须将其设置为数据库名称。如果文件不存在,SQLite将尝试创建它。SQLite还支持内存和临时数据库。只需分别为数据库名称传递“:memory:”或空字符串。
SQLite在多用户和多事务方面有一些限制。如果您尝试从不同的事务编写/读取资源,则应用程序可能会冻结,直到事务提交或回滚。Qt SQLite驱动程序将重试写入锁定资源,直到达到超时(请参阅setConnectOptions()
中的QSQLITE_BUSY_TIMEOUT
)。
在SQLite中,任何列都可以存储任何类型的数据,除了INTEGER PRIMARY KEY列。例如,一个声明为INTEGER的列可能在某一行中包含整数值,在下一行中包含文本值。这是因为SQLite将值的类型与其值本身相关联,而不是与其存储的列相关联。结果是,QSqlField::type()返回的类型仅表示字段的推荐类型。不应从这些值中推断出实际类型,而应检查单个值的类型。
在执行选择时,驱动程序将锁定以更新。当使用QSqlTableModel
时可能会出现问题,因为Qt的项视图会按需获取数据(对于QSqlTableModel
,则是通过QSqlQuery::fetchMore())。
您可以在http://www.sqlite.org上找到有关SQLite的信息。
连接选项#
Qt SQLite 插件尊重以下连接选项
属性
可能的值
QSQLITE_BUSY_TIMEOUT
繁忙处理程序超时(毫秒),值为 <= 0:禁用,有关更多信息,请参阅SQLite 文档
QSQLITE_USE_QT_VFS
如果设置,则使用 Qt 的 VFS 打开数据库,允许使用 QFile 打开数据库。这样它可以从任何读写位置(例如android 共享存储)打开数据库,也可以从只读资源(例如 qrc 或 android assets)打开。请注意,当从只读资源打开数据库时,请确保还添加了 QSQLITE_OPEN_READONLY 属性。否则,将无法打开它。
QSQLITE_OPEN_READONLY
如果设置,则数据库将以只读模式打开,如果不存在数据库则会失败。否则,数据库将以读写模式打开,如果数据库文件尚不存在,则会创建数据库(默认值)
QSQLITE_OPEN_URI
所给的文件名将被解释为 URI,请参阅SQLITE_OPEN_URI
QSQLITE_ENABLE_SHARED_CACHE
如果设置,则数据库将以共享缓存模式打开,否则以私有缓存模式打开
QSQLITE_ENABLE_REGEXP
如果设置,插件定义了一个名为“regex”的函数,可以在查询中使用,使用 QRegularExpression 对正则表达式查询进行评估
QSQLITE_NO_USE_EXTENDED_RESULT_CODES
禁用 SQLite 中的 扩展结果代码 功能
QSQLITE_ENABLE_NON_ASCII_CASE_FOLDING
如果设置,插件将使用 QString 函数替换“lower”和“upper”函数,以正确折叠非_ascii 字符
QSQLITE_OPEN_NOFOLLOW
如果设置,则不允许数据库文件名包含符号链接
如何构建 QSQLITE 插件#
将 SQLite 版本 3 包括在 Qt 的第三方库中。可以通过将 -DFEATURE_system_sqlite=OFF
参数传递给 qt-cmake
命令行来构建它。
如果您不想使用 Qt 中包含的 SQLite 库,可以在 qt-cmake
命令行中传递 -DFEATURE_system_sqlite=ON
以使用操作系统的 SQLite 库。如果适用,建议这样做,因为这可以减少安装大小,并删除您需要跟踪的安全咨询的一个组件。
在 Unix 和 macOS 上(将 $SQLITE
替换为 SQLite 所在的目录)
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_source_directory>/qtbase/src/plugins/sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>/<platform> -DFEATURE_system_sqlite=ON -DCMAKE_INCLUDE_PATH="$SQLITE/include" -DCMAKE_LIBRARY_PATH="$SQLITE/lib" cmake --build . cmake --install .
在 Windows 上(假设 SQLite 已安装在此:C:\SQLITE
)
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DFEATURE_system_sqlite=ON -DCMAKE_INCLUDE_PATH="C:\SQLITE\include" -DCMAKE_LIBRARY_PATH="C:\SQLITE\lib" cmake --build . cmake --install .
启用 REGEXP 运算符#
SQLite 具有内置的 REGEXP 操作。然而,所需的实现必须由用户提供。为了方便起见,可以在数据库连接之前通过设置连接选项 QSQLITE_ENABLE_REGEXP
来启用默认实现。然后,类似“列 REGEXP '模式'”之类的 SQL 语句基本上扩展成了 Qt 代码
column.contains(QRegularExpression("pattern"))
为了提高性能,正则表达式会被内部缓存。默认的缓存大小是25,但可以通过选项值更改。例如,传递“QSQLITE_ENABLE_REGEXP=10
”可以将缓存大小减少到10。
QSQLITE 文件格式兼容性#
SQLite的小版本发布有时会破坏文件格式的向前兼容性。例如,SQLite 3.3可以读取使用SQLite 3.2创建的数据库文件,但使用SQLite 3.3创建的数据库无法被SQLite 3.2读取。请参考SQLite文档和变更日志以获取有关版本间文件格式兼容性的信息。
Qt的小版本发布通常会遵循SQLite的小版本发布,同时Qt的修复版本发布会遵循SQLite的修复版本发布。因此,修复版本既具有向后兼容性又具有向前兼容性。
要强制SQLite使用特定的文件格式,需要构建并提供自己的数据库插件,如下所示。可以在构建SQLite时通过设置SQLITE_DEFAULT_FILE_FORMAT
定义来强制一些SQLite版本写入特定的文件格式。
适用于Mimer SQL版本11及更高版本的QMIMER#
Qt Mimer SQL插件使得与Mimer SQL RDBMS一起工作成为可能。Mimer SQL提供符合国际ISO SQL标准的轻量级、可扩展和健壮的关系型数据库解决方案。Mimer SQL可在Windows、Linux、macOS、OpenVMS以及QNX、Android和嵌入式Linux等几个嵌入式平台上使用。
Mimer SQL完全支持Unicode。要使用Unicode数据,必须使用国家字符(NCHAR)、国家字符可变长度(NVARCHAR)或国家字符大对象(NCLOB)类型。有关Mimer SQL和Unicode的更多信息,请参阅https://developer.mimer.com/features/multilingual-support
QMIMER 存储过程支持#
Mimer SQL根据SQL标准(PSM)拥有存储过程,该插件完全支持IN、OUT、INOUT参数以及结果集过程。
带有INOUT和OUT参数的示例存储过程
create procedure inout_proc (INOUT param1 INT, OUT param2 INT) BEGIN set param1 = param1 * 2; set param2 = param1 * param1; END
访问INOUT和OUT值的源代码
db = QSqlDatabase() query = QSqlQuery() i1 = 10, i2 = 0 query.prepare("call qtestproc(?, ?)") query.bindValue(0, i1, QSql.InOut) query.bindValue(1, i2, QSql.Out) query.exec()
如何在Unix和macOS上构建QMIMER插件#
您需要Mimer SQL头文件和共享库。可以通过安装位于https://developer.mimer.com上的任何Mimer SQL变体来获取它们。
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DMimer_INCLUDE_DIR="/usr/include" -DMimer_LIBRARIES="/usr/lib/libmimer.so" cmake --build . cmake --install .
如何在Windows上构建QMIMER插件#
您需要Mimer SQL头文件和共享库。可以通过安装位于https://developer.mimer.com上的任何Mimer SQL变体来获取它们。
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DMimer_INCLUDE_DIR="C:\Program Files\Mimer SQL Experience 11.0\dev\include" -DMimer_LIBRARIES="C:\Program Files\Mimer SQL Experience 11.0\dev\lib\amd64\mimapi64.lib|C:\Program Files\Mimer SQL Experience 11.0\dev\lib\x86\mimapi32.lib" cmake --build . cmake --install .
QIBASE 用于Borland InterBase#
Qt InterBase插件使得可以访问InterBase和Firebird数据库。InterBase可以作为客户端/服务器使用,也可以在没有服务器的情况下使用,在这种情况下,它将在本地文件上运行。在建立连接之前,数据库文件必须存在。Firebird必须与服务器配置一起使用。
请注意,无论数据库文件存储在本地还是另外一台服务器上,InterBase都要求您指定数据库文件的完整路径。
连接选项#
Qt Borland InterBase插件遵循以下连接选项
属性
可能的值
ISC_DPB_SQL_ROLE_NAME
指定登录角色名称
如何在Unix和macOS上构建QMIMER插件#
db = QSqlDatabase() db.setHostName("MyServer") db.setDatabaseName("C:\\test.gdb")
构建此插件需要InterBase/Firebird的开发头文件和库。
由于与GPL的许可不兼容,Qt开源版的用户不允许将此插件链接到InterBase的商业版。请使用Firebird或InterBase的免费版。
QIBASE 存储过程#
InterBase/Firebird 将输出值作为结果集返回,因此在调用存储过程时,只需要通过 bindValue()
绑定 IN 值。可以通过 value()
获取 RETURN/OUT 值。示例
q = QSqlQuery() q.exec("execute procedure my_procedure") if q.next(): print(q.value(0) # outputs the first RETURN/OUT value)
如何在 Unix 和 macOS 上构建 QIBASE 插件#
假设 InterBase 或 Firebird 安装在 /opt/interbase
如果您正在使用 InterBase
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_source_directory>/qtbase/src/plugins/sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>/<platform> -DInterbase_INCLUDE_DIR="/opt/interbase/include" -DInterbase_LIBRARY="/opt/interbase/lib/libgds.<so|dylib>" cmake --build . cmake --install .
如果您正在使用 Firebird,必须显式设置 Firebird 库
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_source_directory>/qtbase/src/plugins/sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>/<platform> -DInterbase_INCLUDE_DIR="/opt/interbase/include" -DInterbase_LIBRARY="/opt/interbase/lib/libfbclient.<so|dylib>" cmake --build . cmake --install .
如何在 Windows 上构建 QIBASE 插件#
假设 InterBase 或 Firebird 安装在 C:\interbase
如果您正在使用 InterBase
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DInterbase_INCLUDE_DIR="C:\interbase\include" -DInterbase_LIBRARY="C:\interbase\gds.lib" cmake --build . cmake --install .
如果您正在使用 Firebird
mkdir build-sqldrivers cd build-sqldrivers qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DInterbase_INCLUDE_DIR="C:\interbase\include" -DInterbase_LIBRARY="C:\interbase\lib\fbclient_ms.lib" cmake --build . cmake --install .
请注意,C:\interbase\bin
必须在 PATH
中。
故障排除#
您应该始终使用与您项目编译器相同的编译器编译的客户端库。如果您无法自行编译客户端库的源分布,请确保预编译库与您的编译器兼容。如果否则,您将获得大量的“未定义符号”错误。一些编译器有转换库的工具,例如 Borland 提供了工具 COFF2OMF.EXE
用于将使用 Microsoft Visual C++ 生成库转换为库。
如果插件编译成功但不能加载,请确保满足以下要求
确保插件位于正确的目录中。您可以使用 QApplication::libraryPaths() 确定Qt在哪里查找插件。
确保 DBMS 的客户端库在系统中可用。在 Unix 上,运行
ldd
命令并将插件的名称作为参数传递,例如ldd libqsqlmysql.so
。如果您找不到任何客户端库,您将得到警告。在 Windows 上,您可以使用 Visual Studio 的依赖关系分析器。使用 Qt Creator,您可以在 项目 选项板的 运行 部分更新PATH
环境变量,以包含包含客户端库的文件夹的路径。通过定义
QT_DEBUG_PLUGINS
来使用调试版 Qt 进行编译,以在加载插件时获取非常详尽的调试输出。
确保您已遵循部署插件的指南。
如何编写自己的数据库驱动程序#
QSqlDatabase
负责加载和管理数据库驱动插件。当添加数据库时(参见 addDatabase()
),将加载适当的驱动插件(使用 QSqlDriverPlugin
)。QSqlDatabase
依赖于驱动插件来提供用于 QSqlDriver
和 QSqlResult
的接口。
QSqlDriver
是一个抽象基类,它定义了SQL数据库驱动程序的功能。这包括如 open()
和 close()
等函数。 QSqlDriver
负责连接到数据库、建立适当的环境等。此外, QSqlDriver
还可以创建适合特定数据库API的 QSqlQuery
对象。《a class="reference internal" href="../PySide6/QtSql/QSqlDatabase.html#PySide6.QtSql.QSqlDatabase" title="PySide6.QtSql.QSqlDatabase">QSqlDatabase
将许多函数调用直接转发到 QSqlDriver
,该类提供具体的实现。
QSqlResult
是一个抽象基类,它定义了SQL数据库查询的功能。这包括如 SELECT
,UPDATE
和 ALTER
TABLE
等语句。 QSqlResult
包含了如 next()
和 value()
等函数。《a class="reference internal" href="../PySide6/QtSql/QSqlResult.html#PySide6.QtSql.QSqlResult" title="PySide6.QtSql.QSqlResult">QSqlResult
负责向数据库发送查询,返回结果数据等。《a class="reference internal" href="../PySide6/QtSql/QSqlQuery.html#PySide6.QtSql.QSqlQuery" title="PySide6.QtSql.QSqlQuery">QSqlQuery
将许多函数调用直接转发到 QSqlResult
,该类提供具体的实现。
QSqlDriver
和 QSqlResult
密切相关。在实现 Qt SQL 驱动时,这两个类必须被继承,并且每个类中的抽象虚拟方法都必须实现。
要将 Qt SQL 驱动作为插件实现(以便在运行时由 Qt 库识别和加载),驱动程序必须使用 Q_PLUGIN_METADATA() 宏。有关更多信息,请参阅如何创建 Qt 插件。您还可以查看 Qt 提供的 SQL 插件中是如何实现这一点的,这些插件位于 QTDIR/qtbase/src/plugins/sqldrivers
。
以下代码可以作为 SQL 驱动的骨架使用
class XyzResult(QSqlResult): # public XyzResult(QSqlDriver driver) super().__init__(driver) ~XyzResult() {} # protected QVariant data(int /* index */) override { return QVariant(); } bool isNull(int /* index */) override { return False; } bool reset(QString /* query */) override { return False; } bool fetch(int /* index */) override { return False; } bool fetchFirst() override { return False; } bool fetchLast() override { return False; } int size() override { return 0; } int numRowsAffected() override { return 0; } QSqlRecord record() override { return QSqlRecord(); } class XyzDriver(QSqlDriver): # public XyzDriver() {} ~XyzDriver() {} bool hasFeature(DriverFeature /* feature */) override { return False; } bool open(QString /* db */, QString /* user */, QString /* password */, QString /* host */, int /* port */, QString /* options */) override { return False; } def close(): pass QSqlResult createResult() override { return XyzResult(self); }