You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt 5.15.4中通过QSqlDatabase与QOCI插件在Oracle 19c启动只读事务可行吗?

Qt QOCI 实现只读事务(无需修改Qt源码)

问题背景

环境:Qt 5.15.4、基于OCI 12.2构建的QOCI插件、Oracle 19c数据库,基础数据库连接功能正常。

已尝试两种方式均未达到预期:

  • 直接执行SET TRANSACTION READ ONLY:无报错,但后续执行INSERT语句未触发预期的ORA-01456错误;
  • 先调用db.transaction()再执行SET TRANSACTION READ ONLY:触发ORA-01453错误(提示SET TRANSACTION必须是事务的第一条语句)。

已知修改QOCIDriver::beginTransaction()中OCITransStart()的参数为OCI_TRANS_READONLY可生效,但需无需修改Qt源码的实现方案。

可行解决方案

核心思路

不依赖Qt内置的transaction()方法,直接通过Qt提供的接口获取原生OCI句柄,手动启动只读事务,同时保持Qt数据库连接的上下文一致性。

具体实现代码

#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlDriver>
#include <oci.h>

// 获取目标数据库连接
QSqlDatabase db = QSqlDatabase::database("your_connection_name");
if (!db.isOpen()) {
    // 处理连接未打开逻辑
    return;
}

// 获取原生OCI环境句柄和连接句柄
OCIEnv* ociEnv = reinterpret_cast<OCIEnv*>(db.driver()->handle());
OCIError* ociErr = nullptr;
// 初始化错误句柄
OCIHandleAlloc(ociEnv, reinterpret_cast<void**>(&ociErr), OCI_HTYPE_ERROR, 0, nullptr);
OCISvcCtx* ociConn = reinterpret_cast<OCISvcCtx*>(db.driver()->handle(QSqlDriver::ConnectionHandle));

// 启动只读事务
sword transStatus = OCITransStart(ociEnv, ociErr, ociConn, 0, OCI_TRANS_READONLY);
if (transStatus != OCI_SUCCESS && transStatus != OCI_SUCCESS_WITH_INFO) {
    // 处理事务启动失败逻辑
    OCIHandleFree(ociErr, OCI_HTYPE_ERROR);
    return;
}

// 执行测试INSERT语句(此时会触发ORA-01456)
QSqlQuery query(db);
if (!query.exec("INSERT INTO your_table (col) VALUES ('test')")) {
    qDebug() << query.lastError().text(); // 应输出ORA-01456错误
}

// 结束事务
db.rollback();
OCIHandleFree(ociErr, OCI_HTYPE_ERROR);

关键说明

  • 直接执行SET TRANSACTION READ ONLY无效的原因:Qt QOCI插件默认会在执行第一条DML/DDL语句时自动启动读写事务,覆盖手动设置的只读属性;
  • 此方案通过原生OCI接口启动事务,绕过了Qt默认的事务启动逻辑,确保事务属性为只读;
  • 事务结束时仍可使用Qt的commit()或rollback()方法,Qt会正确调用OCI的事务结束接口,无需额外处理。

内容的提问来源于stack exchange,提问作者Lars

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 02:05:35