QACI编程概述¶
QACI依赖的动态库¶
QQt的应用程序在加载qsqlaci动态库的时候需要同时加载aci。这里有两种方法让aci正确加载:
- 隐式加载。Windows_64环境下把aci.dll放到Path环境变量下;Linux_64环境下把libaci.so放到LD_LIBRARY_PATH下。
- 显示加载。如果Path环境变量或者LD_LIBRARY_PATH下没有aci,可以在应用程序加载qsqlaci动态库的代码前用函数显示加载,见应用举例。显示加载的好处在于如果QACI没有正确加载,可以先检查aci是否正确加载,排除QACI没有正确加载的部分原因。
QACI的存放路径¶
Qt指定了数据库驱动动态库路径。路径为:Qt开发环境/plugins/sqldrivers
以Qt5.5.1为例:
Windows_64环境:c:QTQt5.5.15.5msvc2013_64pluginssqldrivers
Linux_64环境: /opt/Qt5.5.1/5.5/gcc_64/plugins/sqldrivers
QACI的数据结构¶
当使用QACI接口来连接神通数据库的时候,常用的类有以下几种:
| 类名 | 引用的头文件 | 解释 |
|---|---|---|
| QSqlDatabase | #include <QSqlDatabase> | 表示一个数据库连接 |
| QSqlQuery | #include <QSqlQuery> | 提供对sql语句的操作和执行 |
| QSqlRecord | #include <QSqlRecord> | 封装一个数据库记录 |
| QSqlDriver | #include <QSqlDriver> | 连接特定数据库的抽象基类 |
| QSqlIndex | #include <QSqlIndex> | 提供函数操作和解释数据库索引 |
QACI事务¶
QACI的事务默认为自动提交,即执行了QSqlQuery::exec方法后,事务会被自动提交,如果想显示开启事务并手动提交,需要知识QSqlDatabase::database().transaction()和QSqlDatabase::database().commit()、QSqlDatabase::database().rollback()方法。
QACI支持数据类型¶
| 序号 | 数据库类型 | QT类型 | C类型 | 备注 |
|---|---|---|---|---|
| 1 | Smallint | QVariant::Int | Short int | |
| 2 | Int | QVariant::Int | Int | |
| 3 | Bigint | QVariant::Longlong | Long long | |
| 4 | Double precision | QVariant::Double | double | |
| 5 | Decimal/Number(p,s) | QVariant::Double | double | |
| 6 | Float/Float(n) | QVariant::Double | double | |
| 7 | Char(n) | QVariant:: QString | Char * | |
| 8 | varchar(n)/ varchar2(n) | QVariant:: QString | Char * | |
| 9 | binary | QVariant::QByteArray | Char * | |
| 10 | varbinary | QVariant::QByteArray | Char * | |
| 11 | Time(p) | QVariant::Time | ———— | |
| 12 | date | QVariant::Date | ———— | |
| 13 | Timestamp(p) | QVariant::DateTime | ———— | 数据库精度p>=6,但QT只支持3为小数 |
| 14 | Interval day to second | QVariant:: QString | Char * | 数据库默认date只有年月日,如果是Oracle兼容模式并设置了DATEFORMAT属性,可包含时分秒,不支持毫秒 |
| 15 | Interval year to month | QVariant:: QString | Char * | 数据库精度p>=6,但QT只支持3为小数 |
| 16 | BLOB | QVariant::QByteArray | Char * | Interval类型QT无对于类型,可通过字符串方式读写 |
| 17 | CLOB | QVariant:: QString | Char * | 数据库支持4GB,QByteArray/ QString支持的大小由内存决定,但时间情况存储文件较大时,QT处理效率比较低。 |
QACI数据转换¶
QACI对数据库操作的支持情况¶
不支持的操作¶
- 不支持一次执行多次sql
因为QACI是底层为aci接口,aci为仿Oracle的OCI接口,而OCI接口是不支持多条sql同时执行的,aci为了保持一致性,也不支持,因此QACI也是不支持的。 比如:
query.exec(insert into test values(1, 'aaa'); insert into test values(2, 'bbb');") ;不支持
在特殊场景中,如果想一次执行多个sql(非返回结果集的SQL),可用匿名块实现,比如:
query.exec(begin insert into test values(1, 'aaa'); insert into test values(2, 'bbb'); end;") ;
- 不支持lastInsertId操作
QSqlQuery类有个lastInsertId方法,由于返回最后插入数据的RowId,目前不支持,处理办法为可以通过数据库的returing语法实现,比如:
QSqlQuery query;
query.prepare("insert into test values(?,?) returning a into ? ");
query.bindValue(0,999);
query.bindValue(1,"移植3");
query.bindValue(2,0,QSql::Out);
query.exec();
qDebug()<<query.boundValue(2).toInt();
db.commit();
- 二进制数据类型的返回
目前因为神通的aci接口中的ACIStmtGetPieceInfo和ACIStmtSetPieceInfo接口存在问题,导致QACI无法获得binary和varbianry类型的数据,后续支持。
- Refcursor类型无法操作
QT原生自带的QOCI也无法操作Oracle的sys_refcursor游标,后续可考虑支持。
/*
create or replace procedure prefcursor(id int ,tname out varchar(30),rescur out sys_refcursor)
as
begin
tname = 'test';
open rescur for select *from test;
end;
/
对于prefcursor存储过程,rescur为out的游标参数,目前是没有办法获得的。
额外支持的操作¶
以下罗列QACI相对于QOCI接口增加的功能
- 支持Bool类型
神通数据库中有bool数据库类型,QOCI不支持,通过修改可以支持,获取方式如下:
//create table tbbool( a int,b bool);
QSqlQuery query;
query.exec("truncate table tbbool");
query.prepare("insert into tbbool values(?,?)");
query.bindValue(0,13);
query.bindValue(1,true);
query.bindValue(0,15);
query.bindValue(1,false);
query.exec();
- 支持time、date、timestamp类型
原生QOCI只支持QDateTime类型,且不支持对于time类型和timestamp类型的毫秒精度,通过修改,可支持这三种类型,同时毫秒精度可支持3为小数(因为QDateTime的格式化字符串中,毫秒值精确到了3位):
//create table tbtime( a int,b date,c time,d timestamp(6));
QSqlQuery query;
query.exec("drop table tbtime");
query.exec("create table tbtime( a int,b date,c time,d timestamp(6))");
query.prepare("insert into tbtime values(?,?,?,?)");
QDate c11 = QDate::currentDate();
QTime c21 = QTime::currentTime();
QDateTime c31 = QDateTime::currentDateTime();
query.bindValue(0,11);
query.bindValue(1,c11);
query.bindValue(2,c21);
query.bindValue(3,c31);
query.exec();