SQL数据库驱动程序

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

支持的数据库

下面的表格列出了Qt附带的驱动程序

驱动程序名称DBMS
QDB2IBM DB2(版本7.1及以上)
QIBASEBorland InterBase / Firebird
QMYSQL / MARIADBMySQL或MariaDB(版本5.6及以上)
QOCIOracle Call Interface Driver(版本12.1及以上)
QODBC开放数据库连接(ODBC)- Microsoft SQL Server和其他ODBC兼容数据库
QPSQLPostgreSQL(版本7.3及以上)
QSQLITESQLite版本3
QMIMERMimer SQL(版本11及以上)

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_PATHCMAKE_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_PATHCMAKE_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级别支持存储过程,但没有用于控制IN、OUT和INOUT参数的API。因此,必须使用SQL命令而不是QSqlQuery::bindValue来设置和读取参数。

示例存储过程

create procedure qtestproc (OUT param1 INT, OUT param2 INT)
BEGIN
    set param1 = 42;
    set param2 = 43;
END

访问OUT值的源代码

QSqlQuery q;
q.exec("call qtestproc (@outval1, @outval2)");
q.exec("select @outval1, @outval2");
if (q.next())
    qDebug() << 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指定要使用的套接字或命名管道,即使是称为UNIX_SOCKET,它也可以在Windows上使用
MYSQL_SHARED_MEMORY_BASE_NAME指定的要使用的共享内存段名
MYSQL_OPT_RECONNECTTRUE或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安装(x86或x64)匹配的MySQL C连接器。安装后,检查所需的文件是否存在

  • <MySQL dir>/lib/libmysql.lib
  • <MySQL目录>/lib/libmysql.dll
  • <MySQL目录>/include/mysql.h

以及对于MariaDB

  • <MariaDB目录>/lib/libmariadb.lib
  • <MariaDB目录>/lib/libmariadb.dll
  • <MariaDB目录>/include/mysql.h

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

按照以下步骤构建插件(这里假设<MySQL目录>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还需要通过vcredist.exe安装的MSVC运行时库。

QOCI用于Oracle调用接口(OCI)

Qt OCI插件支持根据所用即时客户端的版本连接到Oracle数据库。这取决于Oracle表明它支持什么。插件将自动检测数据库版本并相应地启用功能。

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

OCI用户身份验证

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

当使用QSqlDatabase打开连接时,留空用户名和密码以使用外部凭据身份验证。

OCI BLOB/LOB 支持

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

应使用预定义查询或QSqlTableModel(使用预定义查询内部执行)来执行BLOB的插入,其中BLOB绑定到占位符。

连接选项

Qt OCI插件遵循以下连接选项

属性可能值
OCI_ATTR_PREFETCH_ROWS将OCI属性OCI_ATTR_PREFETCH_ROWS设置为指定的值
OCI_ATTR_PREFETCH_MEMORY将OCI属性OCI_ATTR_PREFETCH_MEMORY设置为指定的值
OCI_AUTH_MODEOCI_SYSDBA:为了访问SYSDBA而进行身份验证
OCI_SYSOPER:为了访问SYSOPER而进行身份验证
OCI_DEFAULT:使用正常访问进行身份验证
有关访问模式的信息,请参阅OCISessionBegin

如何在Unix和macOS上构建OCI插件

您只需要“ - 基本版”和“即时客户端包 - SDK”。

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

  • libclntsh.<so|dylib>(所有版本)

告诉qt-cmake在哪里查找Oracle头文件和共享库,并构建。

我们假设您已安装了即时客户端包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插件

在选择Oracle Client安装光盘中的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)

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

注意: 如果有可用,您应该使用本地驱动程序而不是ODBC驱动程序。如果没有本地区域驱动程序,ODBC支持可以用作兼容数据库的备用方案。

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

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

QODBC插件需要一个符合ODBC标准的2.0或更高版本的ODBC驱动程序管理器。某些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调用跟踪。

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

ODBC 存储过程支持

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

// STORED_PROC uses the return statement or returns multiple result sets
QSqlQuery query;
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_MODESQL_MODE_READ_ONLY:以只读模式打开数据库
SQL_MODE_READ_WRITE:以读/写模式打开数据库(默认)
SQL_ATTR_LOGIN_TIMEOUT登录期间等待数据库连接的秒数(值为 0 将无限期等待)
SQL_ATTR_CONNECTION_TIMEOUT等待任何数据库请求的秒数(值为 0 将无限期等待)
SQL_ATTR_CURRENT_CATALOG用于此连接的目录(数据库)
SQL_ATTR_METADATA_IDSQL_TRUE:将目录函数的字符串参数视为标识符
SQL_FALSE:目录函数的字符串参数不被视为标识符
SQL_ATTR_PACKET_SIZE指定字节数据包大小
SQL_ATTR_TRACEFILE包含跟踪文件名的字符串
SQL_ATTR_TRACESQL_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_VERSIONSQL_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,则会自动使用 Unicode。请注意,驱动程序仅支持 UTF-8 编码。如果您的数据库使用任何其他编码,则服务器必须编译有 Unicode 转换支持。

Unicode 支持始于 PostgreSQL 版本 7.1,并且只有在服务器和客户端库都已编译有多字节支持的情况下才会工作。有关如何设置启用了多字节的 PostgreSQL 服务器的更多信息,请参阅 PostgreSQL 管理员指南第五章。

QPSQL 区分大小写

PostgreSQL 数据库只有在创建表时表名或字段名被引号括起来时才会尊重大小写。例如,一个如下的 SQL 查询

CREATE TABLE "testTable" ("id" INTEGER);

将确保它能以相同的格式访问。如果创建表或字段名时没有引号,则实际的表名或字段名将采用小写。当使用 QSqlDatabase::record() 或 QSqlDatabase::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 调用 QSqlQuery::setForwardOnly 将不会有任何效果。

警告: 如果您使用 PostgreSQL 版本 9.2 或更高版本构建 QPSQL 插件,则您必须将应用程序与 9.2 或更高版本的 libpq 一起分发。否则,加载 QPSQL 插件将失败,并显示以下消息

QSqlDatabase: QPSQL driver not loaded
QSqlDatabase: available drivers: QSQLITE QMYSQL QMARIADB QODBC QPSQL
Could not create database object

在只向前模式导航结果时,QSqlResult 的句柄可能会更改。使用 SQL 结果的低级句柄的应用程序必须在每次调用 QSqlResult 的任何获取函数之后获取一个新的句柄。例如

QSqlQuery query;
QVariant v;
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) {
        PGresult *handle = *static_cast<PGresult **>(v.data());
        if (handle) {
            // Do something...
        }
    }
}

在 PostgreSQL 中读取只向前查询的结果时,数据库连接不能用于执行其他查询。这是 libpq 库的限制。例如

int value;
QSqlQuery query1;
query1.setForwardOnly(true);
query1.exec("select * FROM table1");
while (query1.next()) {
    value = query1.value(0).toInt();
    if (value == 1) {
        QSqlQuery query2;
        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 插件遵守 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中调用存储过程时,建议使用单向查询(参见QSqlQuery::setForwardOnly()).

连接选项

Qt IBM DB2插件支持以下连接选项

属性可能值
SQL_ATTR_ACCESS_MODESQL_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 for SQLite(版本3及以上)

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

SQLite对多用户和多事务有一些限制。如果您尝试从不同的事务中读取/写入资源,则您的应用程序可能会冻结,直到某一事务提交或回滚。Qt SQLite驱动程序将在遇到超时之前尝试写入被锁定的资源(见QSqlDatabase::setConnectOptions中的QSQLITE_BUSY_TIMEOUT)。

在SQLite中,任何列(整数主键列除外)都可以存储任何类型的值。例如,一个声明为整数的列在一行中可能包含整数值,而在下一行中可以包含文本值。这是因为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 资产)打开数据库。请注意,当从只读资源中打开数据库时,请务必添加 qsqlitedb_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 插件

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

如果您不想使用 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定义来强制写入特定的文件格式。

QMIMER for Mimer SQL版本11及以上

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值的源代码

    QSqlDatabase db;
    QSqlQuery query;
    int 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 for Borland InterBase

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

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

连接选项

Qt Borland InterBase插件遵守以下连接选项

属性可能值
ISC_DPB_SQL_ROLE_NAME指定登录角色名称

如何构建QIBASE插件

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

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

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

QIBASE存储过程

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

QSqlQuery q;
q.exec("execute procedure my_procedure");
if (q.next())
    qDebug() << 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提供了将用Microsoft Visual C++生成的库进行转换的工具COFF2OMF.EXE

如果插件编译成功但无法加载,请确保满足以下要求

  • 确保插件位于正确的目录中。您可以使用QApplication::libraryPaths()来确定Qt查找插件的路径。
  • 确保DBMS的客户库在系统中可用。在Unix上,运行命令ldd并将插件名作为参数传递,例如ldd libqsqlmysql.so。如果找不到任何客户库,您将收到警告。在Windows上,您可以使用Visual Studio的依赖项分析器。使用Qt Creator,您可以在项目面板的运行部分更新PATH环境变量,以包含包含客户库的文件夹的路径。
  • 使用定义了QT_DEBUG_PLUGINS的Qt编译以在加载插件时得到非常详细的调试输出。

请确保您已遵循插件部署指南。

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

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

QSqlDriver是一个抽象基类,它定义了SQL数据库驱动器的功能。这包括如QSqlDriver::open()和QSqlDriver::close()之类的函数。《a href="qsqldriver.htmltranslate="no"">QSqlDriver负责连接到数据库,建立适当的环境等。此外,《a href="qsqldriver.html" translate="no">QSqlDriver可以创建适用于特定数据库API的QSqlQuery对象。《a href="qsqldatabase.html" translate="no">QSqlDatabase将许多其功能调用直接转发到QSqlDriver,由它提供具体的实现。

QSqlResult是一个抽象基类,它定义了SQL数据库查询的功能。这包括如SELECTUPDATEALTER TABLE之类的语句。《a href="qsqlresult.html" translate="no">QSqlResult包含了QSqlResult::next()和QSqlResult::value()等函数。《a href="qsqlresult.html" translate="no">QSqlResult负责向数据库发送查询,返回结果数据等。《a href="qsqlquery.html" translate="no">QSqlQuery将许多其功能调用直接转发到QSqlResult,由它提供具体的实现。

QSqlDriverQSqlResult 之间紧密相关。在实现 Qt SQL 驱动时,这两个类都必须派生并实现每个类中的抽象虚方法。

为了将 Qt SQL 驱动作为插件实现(以便在运行时由 Qt 库识别和加载),驱动必须使用 Q_PLUGIN_METADATA() 宏。有关更多信息,请参阅 如何创建 Qt 插件。您还可以在 QTDIR/qtbase/src/plugins/sqldrivers 中查看 Qt 提供的 SQL 插件是如何实现的。

以下代码可以作为 SQL 驱动的骨架使用

class XyzResult : public QSqlResult
{
public:
    XyzResult(const QSqlDriver *driver)
        : QSqlResult(driver) {}
    ~XyzResult() {}

protected:
    QVariant data(int /* index */) override { return QVariant(); }
    bool isNull(int /* index */) override { return false; }
    bool reset(const 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() const override { return QSqlRecord(); }
};

class XyzDriver : public QSqlDriver
{
public:
    XyzDriver() {}
    ~XyzDriver() {}

    bool hasFeature(DriverFeature /* feature */) const override { return false; }
    bool open(const QString & /* db */, const QString & /* user */,
              const QString & /* password */, const QString & /* host */,
              int /* port */, const QString & /* options */) override
        { return false; }
    void close() override {}
    QSqlResult *createResult() const override { return new XyzResult(this); }
};

© 2024 Qt 公司。此处包含的文档贡献的版权属于各自的拥有者。此处提供的文档是在 Free Software Foundation 发布的 GNU 自由文档许可协议版本 1.3 的条款下授权的。Qt 及相关标志是芬兰及/或其他国家/地区的 Qt 公司的商标。所有其他商标均为其各自所有者的财产。