警告

本节包含从C++自动翻译到Python的代码片段,可能包含错误。

SQL数据库驱动

如何为支持的数据库配置和安装Qt SQL驱动程序。

Qt SQL 模块使用驱动程序插件与不同的数据库 API 进行通信。由于 Qt 的 SQL 模块 API 是独立于数据库的,所有特定于数据库的代码都包含在这些驱动程序中。Qt 提供了多个驱动程序,并且可以添加其他驱动程序。驱动程序源代码已提供,可以用作编写自己的驱动程序的模型。

支持的数据库

下表列出了Qt中包含的驱动程序:

驱动程序名称

数据库管理系统

QDB2

IBM DB2(版本7.1及以上)

QIBASE

Borland InterBase / Firebird

QMYSQL / MARIADB

MySQL 或 MariaDB(版本 5.6 及以上)

QOCI

Oracle 调用接口驱动程序(版本 12.1 及以上)

QODBC

开放数据库连接 (ODBC) - Microsoft SQL Server 和其他符合 ODBC 标准的数据库

QPSQL

PostgreSQL(版本7.3及以上)

QSQLITE

SQLite 版本 3

QMIMER

Mimer SQL(版本11及以上)

SQLite 是所有平台上测试覆盖率和支持最好的进程内数据库系统。通过 OCI 的 Oracle、PostgreSQL 以及通过 ODBC 或本地驱动程序的 MySQL 在 Windows 和 Linux 上经过了充分测试。对其他系统的支持完整性取决于客户端库的可用性和质量。

注意

要构建一个驱动程序插件,您需要为您的数据库管理系统(DBMS)准备适当的客户端库。这提供了对DBMS暴露的API的访问,通常与DBMS一起提供。大多数安装程序还允许您安装“开发库”,这些是您所需要的。这些库负责与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_PATHCMAKE_LIBRARY_PATH 来指定这些路径。例如,如果您的 MySQL 文件安装在 Windows 上的 C:\mysql-connector-c-6.1.11-winx64 中,则将以下参数传递给配置行的双破折号部分:

C:\Qt\6.0.0\Src\configure.bat -sql-mysql -- -DMySQL_ROOT="C:\mysql-8.0.22-winx64"
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重新检查可用的驱动程序,您可能需要从构建目录中删除CMakeCache.txt

仅编译特定的SQL驱动程序

当Qt已经构建或安装为二进制版本时,可以仅编译特定的SQL驱动程序。但您必须确保安装完全相同版本的Qt源代码(例如通过Qt维护工具)-否则由于API更改,您可能会遇到编译错误。此外,请确保通过执行Windows开始菜单中的适当Qt命令提示符正确设置构建环境。

一个典型的 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和PostgreSQL插件。为了能够在不需要重新构建整个Qt的情况下向Qt安装添加额外的驱动程序,可以在完整的Qt构建目录之外配置和构建qtbase/src/plugins/sqldrivers目录。请注意,无法单独配置每个驱动程序,只能一次性配置所有驱动程序。不过,驱动程序可以单独构建

注意

如果构建完成后要安装插件,您需要指定CMAKE_INSTALL_PREFIX

驱动程序详情

QMYSQL 用于 MySQL 或 MariaDB 5.6 及以上版本

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=libmysqld.来完成。

请参考MySQL文档中的“libmysqld,嵌入式MySQL服务器库”章节,以获取有关MySQL嵌入式服务器的更多信息。

连接选项

Qt MySQL/MariaDB 插件支持以下连接选项:

属性

可能的值

CLIENT_COMPRESS

如果设置,成功认证后切换到压缩协议

CLIENT_FOUND_ROWS

如果设置,发送找到的行而不是受影响的行

CLIENT_IGNORE_SPACE

如果设置,忽略‘(’前的空格

CLIENT_NO_SCHEMA

如果设置,不允许使用 database.table.column

CLIENT_INTERACTIVE

如果设置,客户端被视为交互式

MYSQL_OPT_PROTOCOL

明确指定要使用的协议:MYSQL_PROTOCOL_TCP:使用tcp连接(通过setHostname()指定的ip/主机名) MYSQL_PROTOCOL_SOCKET:通过UNIX_SOCKET中指定的套接字连接 MYSQL_PROTOCOL_PIPE:通过UNIX_SOCKET中指定的命名管道连接 MYSQL_PROTOCOL_MEMORY:通过MYSQL_SHARED_MEMORY_BASE_NAME中指定的共享内存连接

UNIX_SOCKET

指定要使用的套接字或命名管道,即使它被称为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. / libmariadb.。根据你的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_ROOT="/usr/local/mysql"
cmake --build .
cmake --install .

如何在Windows上构建QMYSQL插件

你需要获取MySQL的安装文件(例如MySQL web installerMariaDB C Connector)。运行安装程序,选择自定义安装并安装与你的Qt安装(x86或x64)匹配的MySQL C Connector。安装后检查所需的文件是否存在:

  • dir>/lib/libmysql.lib

  • dir>/lib/libmysql.dll

  • dir>/include/mysql.h

以及对于MariaDB

  • dir>/lib/libmariadb.lib

  • dir>/lib/libmariadb.dll

  • dir>/include/mysql.h

注意

自 MySQL 8.0.19 起,C 连接器不再作为独立的可安装组件提供。相反,您可以通过安装完整的 MySQL 服务器(仅限 x64)或 MariaDB C 连接器 来获取 mysql.hlibmysql.*

按照以下步骤构建插件(这里假设 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_ROOT="C:\mysql-8.0.22-winx64"
cmake --build .
cmake --install .

当你分发你的应用程序时,记得在你的安装包中包含libmysql.dll / libmariadb.dll。它必须放在与应用程序可执行文件相同的文件夹中。libmysql.dll 还需要 MSVC 运行时库,这些库可以通过vcredist.exe安装。

QOCI 用于 Oracle 调用接口 (OCI)

Qt OCI 插件支持连接到 Oracle 数据库,具体取决于所使用的即时客户端版本。这取决于 Oracle 所指示的支持情况。插件将自动检测数据库版本并相应地启用功能。

可以在没有tnsnames.ora文件的情况下连接到Oracle数据库。这要求将数据库SID作为数据库名称传递给驱动程序,并且提供一个主机名。

OCI 用户认证

Qt OCI 插件支持使用外部凭证(OCI_CRED_EXT)进行身份验证。通常,这意味着数据库服务器将使用操作系统提供的用户身份验证,而不是其自身的身份验证机制。

在使用QSqlDatabase打开连接时,将用户名和密码留空以使用外部凭据认证。

OCI BLOB/LOB 支持

二进制大对象(BLOBs)可以读取和写入,但请注意,此过程可能需要大量内存。您应使用仅向前查询来选择LOB字段(参见setForwardOnly())。

插入BLOB应该使用预查询,其中BLOB被绑定到占位符,或者使用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插件

你只需要“ - Basic”和“即时客户端包 - SDK”。

构建驱动程序所需的Oracle库文件:

  • libclntsh. (所有版本)

告诉 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_ROOT="/usr/include/oracle/21/client64"
cmake --build .
cmake --install .

注意

如果您使用的是Oracle Instant Client包,在构建OCI SQL插件时以及运行使用OCI SQL插件的应用程序时,您需要设置LD_LIBRARY_PATH。

如何在Windows上构建OCI插件

在Oracle客户端安装CD中选择“程序员”选项通常足以构建插件。对于某些版本的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_ROOT="C:\oracle"
cmake --build .
cmake --install .

当你运行你的应用程序时,你还需要将oci.dll路径添加到你的PATH环境变量中:

set PATH=%PATH%;C:\oracle

QODBC 用于开放数据库连接 (ODBC)

ODBC 是一个通用接口,允许您使用一个通用接口连接到多个数据库管理系统。QODBC 驱动程序允许您连接到 ODBC 驱动程序管理器并访问可用的数据源。请注意,您还需要为安装在系统上的 ODBC 驱动程序管理器安装和配置 ODBC 驱动程序。然后,QODBC 插件允许您在 Qt 应用程序中使用这些数据源。

注意

如果可用,您应该使用原生驱动程序,而不是ODBC驱动程序。如果没有可用的原生驱动程序,ODBC支持可以作为兼容数据库的备用方案。

在Windows上,默认安装了ODBC驱动程序管理器。对于Unix系统,必须先安装一些实现。请注意,您的应用程序的每个最终用户都必须安装ODBC驱动程序管理器,否则QODBC插件将无法工作。

连接到ODBC数据源时,应将ODBC数据源(DSN)的名称传递给setDatabaseName()函数,而不是实际的数据库名称。也可以传递FILEDSN(*.dsn)文件名或完整的ODBC驱动字符串。传递驱动字符串时,必须确保所有参数(用户名、密码等)都已正确转义。通过QSqlDatabase函数传递用户名或密码时,转义由QODBC插件完成。

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驱动程序可能会导致驱动程序插件出现意外行为。为了避免这个问题,通过在设置连接选项 "SQL_ATTR_ODBC_VERSION=SQL_OV_ODBC3"之前指示ODBC驱动程序表现为3.x驱动程序。请注意,这将影响ODBC驱动程序行为的多个方面,例如SQLSTATEs。在设置此连接选项之前,请查阅您的ODBC文档以了解您可能预期的行为差异。

如果您访问ODBC数据源时速度非常慢,请确保在ODBC数据源管理器中关闭了ODBC调用跟踪。

一些驱动程序不支持可滚动的游标。在这种情况下,只有setForwardOnly()模式下的查询可以成功使用。

ODBC 存储过程支持

使用Microsoft SQL Server时,只有当你将查询的前进模式设置为前进,使用setForwardOnly(),才能访问由存储过程返回的结果集,该存储过程使用返回语句或返回多个结果集。

# 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),必须在ODBC驱动程序管理器中勾选“SQL_WCHAR支持”,否则Oracle会将所有Unicode字符串转换为本地8位表示。

连接选项

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 .

适用于PostgreSQL的QPSQL(版本7.3及以上)

QPSQL 驱动程序支持 PostgreSQL 服务器版本 7.3 及更高版本。

有关PostgreSQL的更多信息,请访问http://www.postgresql.org

QPSQL Unicode支持

QPSQL驱动程序会自动检测您连接的PostgreSQL数据库是否支持Unicode。如果服务器支持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 仅向前查询支持

要使用仅向前查询,您必须使用PostreSQL客户端库版本9.2或更高版本来构建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,这个问题就不会发生。

注意

QSqlDatabase 的一些方法,如 tables()、primaryIndex() 隐式执行 SQL 查询,因此在导航仅向前查询的结果时也不能使用这些方法。

注意

如果检测到查询结果丢失,QPSQL将打印以下警告:

QPSQLDriver::getResult: Query results lost - probably discarded on executing another SQL query.

连接选项

Qt PostgreSQL 插件支持所有在 connect() PostgreSQL 文档中指定的连接选项。

如何在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> -DPostgreSQL_ROOT="/usr/local/pgsql"
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> -DPostgreSQL_ROOT="C:\pgsql"
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将无限等待)

如何在Unix和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 .

QSQLITE 用于 SQLite(版本 3 及以上)

Qt SQLite 插件使得访问 SQLite 数据库成为可能。SQLite 是一个进程内数据库,这意味着不需要数据库服务器。SQLite 操作在单个文件上,该文件在打开连接时必须设置为数据库名称。如果文件不存在,SQLite 将尝试创建它。SQLite 还支持内存和临时数据库。只需分别传递“:memory:”或空字符串作为数据库名称。

SQLite 在多用户和多事务方面有一些限制。如果您尝试从不同的事务中读取/写入资源,您的应用程序可能会冻结,直到一个事务提交或回滚。Qt SQLite 驱动程序将尝试写入被锁定的资源,直到遇到超时(请参阅 QSQLITE_BUSY_TIMEOUTsetConnectOptions() )。

在SQLite中,除了INTEGER PRIMARY KEY列之外,任何列都可以用来存储任何类型的值。例如,声明为INTEGER的列可能在一行中包含整数值,在下一行中包含文本值。这是因为SQLite将值的类型与值本身关联,而不是与存储它的列关联。这样做的结果是,QSqlField::type()返回的类型仅指示字段的推荐类型。不应从此推断实际类型,而应检查各个值的类型。

在执行选择操作时,驱动程序被锁定以进行更新。这可能会在使用QSqlTableModel时导致问题,因为Qt的项目视图根据需要获取数据(在QSqlTableModel的情况下使用QSqlQuery::fetchMore())。

你可以在http://www.sqlite.org上找到关于SQLite的信息。

连接选项

Qt SQLite 插件支持以下连接选项:

属性

可能的值

QSQLITE_BUSY_TIMEOUT

忙碌处理程序超时时间(以毫秒为单位)(val <= 0:禁用),更多信息请参阅SQLite文档

QSQLITE_USE_QT_VFS

如果设置,数据库将使用Qt的VFS打开,这允许使用QFile打开数据库。这样可以从任何读写位置(例如Android共享存储)以及只读资源(例如qrc或Android资产)打开数据库。请注意,当从只读资源打开数据库时,请确保您也添加了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

如果设置,插件将替换函数‘lower’和‘upper’为QString函数,以便正确处理非ASCII字符的大小写折叠

QSQLITE_OPEN_NOFOLLOW

如果设置,数据库文件名不允许包含符号链接

如何构建QSQLITE插件

SQLite 版本 3 作为第三方库包含在 Qt 中。可以通过将 -DFEATURE_system_sqlite=OFF 参数传递给 qt-cmake 命令行来构建它。

如果您不想使用Qt附带的SQLite库,您可以将-DFEATURE_system_sqlite=ON传递给qt-cmake命令行,以使用操作系统的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 之前数据库 连接 打开 来启用默认实现。然后,像“column REGEXP ‘pattern’”这样的 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可以通过在构建SQLite时设置SQLITE_DEFAULT_FILE_FORMAT定义来强制写入特定的文件格式。

适用于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 数据,必须使用列类型 National Character (NCHAR)、National Character Varying (NVARCHAR) 或 National Character Large Object (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 .

用于Borland InterBase的QIBASE

Qt InterBase 插件使得访问 InterBase 和 Firebird 数据库成为可能。InterBase 可以作为客户端/服务器使用,也可以在没有服务器的情况下使用,此时它在本地文件上操作。在建立连接之前,数据库文件必须存在。Firebird 必须与服务器配置一起使用。

请注意,InterBase 要求您指定数据库文件的完整路径,无论它是存储在本地还是另一台服务器上。

连接选项

Qt Borland InterBase 插件支持以下连接选项:

属性

可能的值

ISC_DPB_SQL_ROLE_NAME

指定登录角色名称

如何构建QIBASE插件

db = QSqlDatabase()
db.setHostName("MyServer")
db.setDatabaseName("C:\\test.gdb")

您需要InterBase/Firebird开发头文件和库来构建此插件。

由于与GPL许可证不兼容,Qt开源版的用户不允许将此插件链接到InterBase的商业版。请使用Firebird或InterBase的免费版。

QIBASE 存储过程

InterBase/Firebird 将 OUT 值作为结果集返回,因此在调用存储过程时,只需要通过 bindValue() 绑定 IN 值。RETURN/OUT 值可以通过 value() 获取。示例:

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_ROOT="/opt/interbase/"
cmake --build .
cmake --install .

可选地,使用CMake变量Interbase_INCLUDE_DIRInterbase_LIBRARY直接指定包含路径和库。

如何在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_ROOT="C:\interbase"
cmake --build .
cmake --install .

可选地,使用CMake变量Interbase_INCLUDE_DIRInterbase_LIBRARY直接指定包含路径和库。

请注意,C:\interbase\bin 必须在 PATH 中。

故障排除

您应始终使用与项目相同编译器编译的客户端库。如果无法获取源代码分发版以自行编译客户端库,则必须确保预编译库与您的编译器兼容,否则您将遇到大量“未定义符号”错误。

如果插件的编译成功但之后无法加载,请按照以下步骤查找问题原因:

  1. 确保插件位于正确的目录中。您可以使用 QApplication::libraryPaths() 来确定 Qt 查找插件的位置。

  2. 确保系统上已安装DBMS的客户端库。在Unix上,运行命令ldd并将插件名称作为参数传递,例如ldd libqsqlmysql.so。如果找不到任何客户端库,您将收到警告。在Windows上,您可以使用Visual Studio的依赖项查看器或Dependencies GUI来查找依赖库。使用Qt Creator时,您可以在项目面板的运行部分更新PATH环境变量,以包含客户端库所在文件夹的路径。

  3. 在使用MSVC时,还要确保插件是用正确的构建类型构建的。由于调试版和发布版的MSVC运行时不同,Qt调试版无法加载Qt发布版插件,反之亦然。

  4. 运行编译后的Qt可执行文件时,设置环境变量QT_DEBUG_PLUGINS,以便在加载插件时获得非常详细的调试输出。

  5. 要从SQL子系统中检索可能的调试信息,请通过将环境变量QT_LOGGING_RULES设置为qt.sql.*.debug=true来启用输出。在Windows上工作时,不要忘记启用控制台。有关如何设置日志记录规则的更详细说明,请参见日志记录规则。

确保您已按照部署插件的指南操作。

如何编写自己的数据库驱动程序

QSqlDatabase 负责加载和管理数据库驱动插件。当添加数据库时(参见 addDatabase()),会加载适当的驱动插件(使用 QSqlDriverPlugin)。QSqlDatabase 依赖驱动插件来提供 QSqlDriverQSqlResult 的接口。

QSqlDriver 是一个抽象基类,定义了SQL数据库驱动程序的功能。这包括诸如 open()close() 等函数。QSqlDriver 负责连接到数据库,建立适当的环境等。此外,QSqlDriver 可以创建适合特定数据库API的 QSqlQuery 对象。QSqlDatabase 将其许多函数调用直接转发给提供具体实现的 QSqlDriver

QSqlResult 是一个抽象基类,定义了SQL数据库查询的功能。这包括诸如 SELECTUPDATEALTER TABLE 等语句。QSqlResult 包含诸如 QSqlResult::next() 和 QSqlResult::value() 等函数。QSqlResult 负责向数据库发送查询、返回结果数据等。QSqlQuery 将其许多函数调用直接转发给 QSqlResult,后者提供了具体的实现。

QSqlDriverQSqlResult 是紧密相连的。在实现一个 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); }