应用示例

创建数据库连接

这里使用了QSqlDatabase类,所以需要包含QSqlDatabase头文件,值得注意的是,QT中创建的数据库连接全部是全局连接,在其他主线程和子线程中都可以访问,因此需要注意并发控制(加锁或者在线程中创建自己的数据库连接,QSqlDatabase::addDatabase函数第二个参数为给连接指定一个名称)。

QODBC连接神通数据库的两种方式:

DSN方式:

QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");//加载QODBC驱动

    db.setDatabaseName("ST");

db.setUserName("SYSDBA");

db.setPassword("szoscar55");

DRIVER方式:

    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");//加载QODBC驱动

db.setDatabaseName("DRIVER={OSCAR ODBC DRIVER};DATABASE=OSRDB;SERVER=localhost;UID=SYSDBA;PWD=szoscar55");

连接相关信息查看

qDebug() << "database's name is" << db_st.databaseName();               //数据库名
qDebug() << "database's hostname is" << db_st.hostName();               //主机名
qDebug() << "database's port is" << db_st.port();                               //端口号
qDebug() << "database's username is" << db_st.userName();               //用户名
qDebug() << "database's password is" << db_st.password();               //密码
qDebug() << "database's name is" << db_st.driverName();         //数据库驱动名
qDebug() << "connect option is" << db_st.connectOptions();      //连接选项

插入数据

直接通过sql语句插入

这里使用了QSqlQuery类,所以需要包含QSqlQuery头文件。

QSqlQuery query;
//insert..............................................................................
query.exec("insert into xww_test1 values(1,'i love china')");
query.exec(QString::fromLocal8Bit("insert into xww_test1 values(2,'神舟通用')"));
query.exec(QString::fromLocal8Bit("insert into xww_test1 values(3,'我爱中国')"));

按名字绑定插入

这里使用了QSqlDriver类,所以需要包含QSqlDriver头文件。

//NamedPlaceholders
if(db.driver()->hasFeature(QSqlDriver::NamedPlaceholders))
{
    query.prepare(QString::fromLocal8Bit("insert into xww_test1(c1,c2) values(:c1,:c2)"));
    query.bindValue(":c1",4);
    query.bindValue(":c2",QString::fromLocal8Bit("按名字绑定"));
    query.exec();
}

按位置绑定插入

//PositionalPlaceholders
if(db.driver()->hasFeature(QSqlDriver::PositionalPlaceholders))
{
    query.prepare(QString::fromLocal8Bit("insert into xww_test1(c1,c2) values(?,?)"));
    query.bindValue(0,5);
    query.bindValue(1,QString::fromLocal8Bit("按位置绑定"));
    query.exec();
}

按数组绑定方式插入

//通过邦定数组方式insert........
  query.prepare("insert into xww_test2(a1,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12) "
                "values(:a1,:c1,:c2,:c3,:c4,:c5,:c6,:c7,:c8,:c9,:c10,:c11,:c12)");
  QVariantList a1;
  a1 << -128 << 2 << 3 << 4;
  query.addBindValue(a1);

  QVariantList c1;
  c1 << 2147483647 << 22 << 33 << 44;
  query.addBindValue(c1);

  QVariantList c2;
  c2 << -32768 << 3 << 4<< 5;
  query.addBindValue(c2);

  QVariantList c3;
              qint64 maxint64 = Q_INT64_C(9223372036854775807);
  c3 << maxint64 << 4 << 5<< 6;
  query.addBindValue(c3);

  QVariantList c4;
  c4 << 4.44 << 23424.2323 << 323.2323 << 243243.323;
  query.addBindValue(c4);

  QVariantList c5;
  c5 << 55.55 << 23424.2323 << 323.2323 << 243243.323;
  query.addBindValue(c5);

  QVariantList c6;
  c6 << 6.66 << 23424.2323 << 323.2323 << 243243.323;
  query.addBindValue(c6);

  QVariantList c7;
  c7 << "7:31:13" << "6:31:13" << "12:31:13" << "12:31:13";
  query.addBindValue(c7);

  QVariantList c8;
  c8 << "1998-11-12" << "2000-11-12" << "1999-11-12" << "1999-11-12";
  query.addBindValue(c8);

  QVariantList c9;
  c9 << "1999-11-12 12:31:13" << "2016-11-12 12:31:13" << "2015-11-12 12:31:13" << "2014-11-12 12:31:13";
  query.addBindValue(c9);

  QVariantList c10;
  c10 << "char20" << "Boris" << QString::fromLocal8Bit("清风徐来") << "John";
  query.addBindValue(c10);

  QVariantList c11;
  c11 << "varchar100" << "Boris" << QString::fromLocal8Bit("窗前明月光") << "Kobe";
  query.addBindValue(c11);

  QVariantList c12;
  c12 << "text" << "Boris" << QString::fromLocal8Bit("问君能有几多愁") << "Jordan";
  query.addBindValue(c12);

  //如果没有执行成功
  if(query.execBatch() == false)
  {
      qDebug() << query.lastError();
  }

删除数据

//清空xww_test1表.......................................................
query.exec("delete from xww_test1");

数据查询

获取所有结果

//select...........................................................................
query.exec("select * from xww_test1 order by c1");
QSqlRecord rec = query.record();            //获取select的结果信息
int columncount = rec.count();              //获取列数
qDebug() << "columncount of table xww_test1 is:" << columncount;
//获取所有的列
while(query.next()){
    if(columncount != 0)
    {
        QString columnvalue;
        int i;
        for(i=0;i < (columncount-1);i++)
        {
            columnvalue += (query.value(i).toString() + ",");
        }
        columnvalue += query.value(i).toString();           //最后一列没有不加逗号
        qDebug() << columnvalue;
    }
}

获取特定的结果

//返回全部的属性和结果集........................................................................
query.exec("select * from xww_test1");
//指向第一条记录
if(query.next()){
    int RowNum = query.at();                   //获取query所指向的记录在结果集中的编号
    int ColumnNum = query.record().count(); //获取每条记录的列数,必须添加<QSqlRecord>头文件
    int FieldNum = query.record().indexOf("c2");    //根据列名查询列的编号
    QString column = query.value(0).toString()+","+query.value(FieldNum).toString();
    qDebug() << "row number is:" << RowNum << ",column count is " << ColumnNum << ",column value is:" << column;
}
//指向第二条记录
if(query.seek(1))
{
    qDebug() << "row number is:" << query.at() << ",c1 is:" << query.value(0).toInt() << ",c2 is:" << query.value(1).toString();
}

//指向最后一条记录
if(query.last())
{
    qDebug() << "row number is:" << query.at() << ",c1 is:" << query.value(0).toInt() << ",c2 is:" << query.value(1).toString();
}

满足一定条件的结果集

//满足一定条件的结果集................................................................................
query.prepare("select c2 from xww_test1 where c1= :c1 ");
int test1_c1 = 1;
query.addBindValue(test1_c1);
query.exec();
if(query.next())
{
    qDebug() << "when c1 = 1,c2 = " <<query.value(0).toString();
}

事务操作

这里需要注意一下:QSqlDatabase::database().commit()操作,不管提交正确还是错误,返回值都是true。并且提交错误的时候会自动回滚。

//事务操作........................................................................................
if(QSqlDatabase::database().transaction())//启动事务操作
{
    QSqlQuery query1;                 //必须在开始事务之后,不然执行sql语句时事务标志为false
    query1.exec("insert into xww_test1 values(6,'第六行')");
    query1.exec("insert into xww_test1 values(7,'第七行')");
    query1.exec(QString::fromLocal8Bit("insert into xww_test1 values(5000000000000,'test1中国')"));//第一列int越界
    query1.exec("delete from xww_test1 where c1=6");

    if(!QSqlDatabase::database().commit())//提交。不管提交正确还是错误,返回值都是true。提交错误的时候会自动回滚。
    {
        qDebug() << QSqlDatabase::database().lastError();
        if(!QSqlDatabase::database().rollback())//回滚。代码不会走到这里。
        {
            qDebug() << QSqlDatabase::database().lastError();
        }
    }
}

Returning语法使用

神通支持Returning语法,用于返回插入/更新相关列的值,常用于返回主键ID列,使用方法如下:

//create table test( a int ,b varchar(30);
      //returning int
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();


//returning varchar
query.prepare("insert into test values(?,?) returning b into ? ");
query.bindValue(0,999);
query.bindValue(1,"移植3");
query.bindValue(2,"",QSql::Out);
query.exec();
qDebug()<<query.boundValue(2).toString();

存储过程调用

神通QODBC支持存储过程、匿名块的调用,并支持返回存储过程的out参数操作:

匿名块

匿名块是一个以begin开头end; 结束的一个SQL块,SQL块里面包含多条sql语句,不能包含返回结果集的查询,select into 是可以的,匿名块执行如下:

query.exec(begin insert into test values(1, 'aaa'); insert into test values(2, 'bbb');  end;") ;

无out参数存储过程

In参数的绑定和insert参数绑定操作完全类似,如下:

/*    create or replace procedure p1( a int ,b varchar2(100)) as
  tmp int;
  begin
  tmp = a;
  dbms_output.put_line(b||a);
  end;
*/

  QSqlQuery query;
  query.prepare("CALL p1(?, ?)");
  query.bindValue(0, 11);
  query.bindValue(1, "aaa");
  query.exec();

有out参数存储过程

  • 返回一个参数
/*    create or replace procedure p2( a int ,b out int) as
  tmp int;
  begin
  b = a;
  end;
  /
*/
QSqlQuery query;
query.prepare("CALL p2(?, ?)");
query.bindValue(0, 22);
query.bindValue(1, 0, QSql::Out);
query.exec();
int i = query.boundValue(1).toInt();
qDebug()<<i;
  • 返回两个参数
/*    create or replace procedure p3( a int ,b out int,c out varchar(30)) as
  tmp int;
  begin
  b = a;
  c='yyyyy'||a;
  end;
/
*/
QSqlQuery query;
QString yy="";
query.prepare("CALL p3(:c1, :c2, :c3)");
query.bindValue(0, 33);
query.bindValue(1, 0, QSql::Out);
query.bindValue(2, yy, QSql::Out);
query.exec();
int ii = query.boundValue(1).toInt();
QString tmp = query.boundValue(2).toString();
qDebug()<<ii<<","<<tmp;

中文数据字典

QODBC支持表名、字段名、约束名为中文的情况下的数据操作:

/*
   create table 中文表(a int 中,文列1 varchar(100));
   alter table 中文表 add CONSTRAINT 中文表pk PRIMARY KEY (中文列1) ;
   insert into 中文表 values(1,'中文1');
   insert into 中文表 values(2,'中文2');
*/
 QSqlQuery query;
 query.exec("select * from 中文表");
 while(query.next()){
     qDebug()<<query.value(0).toInt()<<","<<query.value(1).toString();
     qDebug()<<query.value("a").toInt()<<","<<query.value("中文列1").toString();
 }
qDebug()<<query.executedQuery();


//主键名称为中文时,获取主键也是支持的:
QSqlIndex primarykey_t2 = db.primaryIndex("中文表");
int pk_count1 = primarykey_t2.count();
qDebug() << "name:" << primarykey_t2.name();
for(int i=0;i < pk_count1;i++)
   {
      qDebug() << "fieldname:" << primarykey_t2.fieldName(i);
   }

空值和空串处理

演示如何向数据库插入一个空值,空串,并进行查询:

空值插入

  • 方式一:不绑定的参数即可插入一个NULL值
QSqlQuery query;

query.exec("truncate table test");
query.prepare("insert into test values(?,?) ");
query.bindValue(0,999);
//second不做绑定即为插入一个NULL
query.exec();
  • 方式二:绑定一个类型即可
//int列插入一个空值
query.prepare("insert into test values(?,?) ");
query.bindValue(0,QVariant(QVariant::Int));
query.bindValue(1,"ccc");
query.exec();


// 字符串列插入一个空值
query.prepare("insert into test values(?,?) ");
query.bindValue(0,888);
query.bindValue(1,QVariant(QVariant::String));
query.exec();

批量绑定插入空值

//batch insert NULL
query.prepare("insert into test values(?,?) ");
QVariantList bc1;
bc1<<111<<112<<113;

QVariantList bc2;
bc2<<"a"<<QVariant(QVariant::String)<<"c";

query.addBindValue(bc1);
query.addBindValue(bc2);
query.execBatch();

空串插入

query.prepare("insert into test values(?,?) ");
query.bindValue(0,666);
query.bindValue(1,"");
query.exec();

批量绑定插入空串

//batch insert ""
query.prepare("insert into test values(?,?) ");
QVariantList bc11;
bc11<<111<<112<<113;

QVariantList bc22;
bc22<<"a"<<""<<"c";

query.addBindValue(bc11);
query.addBindValue(bc22);
query.execBatch();

如何判断空值

query.prepare("select * from test ");
query.exec();
while(query.next())
{
    qDebug()<<query.value(1).isNull();
}

各种数据类型操作示例

数值类型操作

对于tinyint、smallint、bigint、double precision、float类型操作:

  • 数值插入
//create table tbnum( a tinyint,b smallint ,c bigint,d double precision,e float);
QSqlQuery query;
query.prepare("insert into tbnum values(?,?,?,?,?)");
long long bigintdata = 922337203685477580;
double doubledata=1234567.1234567;
query.bindValue(0,65);
query.bindValue(1,2);
query.bindValue(2,bigintdata);
query.bindValue(3,doubledata);
query.bindValue(4,4.111);
query.exec();
  • 数值查询
QSqlQuery query;
query.prepare("select * from tbnum");
query.exec();
db.setNumericalPrecisionPolicy(QSql::HighPrecision);
qDebug()<<"uuuuuuu:"<<db.numericalPrecisionPolicy();
while(query.next())
{
    qDebug()<<query.value(0).toInt();
    qDebug()<<query.value(1).toInt();
    qDebug()<<query.value(2).toLongLong();
    qDebug()<<query.value(3).toDouble();
    qDebug()<<query.value(4).toFloat();
}

字符串类型操作

字符串操作比较简单,如下:

//create table test( a int,b varchar(100));
QSqlQuery query;
query.prepare("insert into test values(?,?)");
query.bindValue(0,11);
query.bindValue(1, "aaa");
query.exec();

QString strdata = "bbb";
query.prepare("insert into test values(?,?)");
query.bindValue(0,12);
query.bindValue(1, "aaa");
query.exec();

二进制类型操作

Binary和varbinary二进制类型,操作如下:

  • 二进制类型插入

通过QVariant::ByteArray类型插入数据:

//create table tbbinary( a int,b binary(30),c varbinary(100));
QSqlQuery query;
QString qdata = "ssss";
QVariant c1 = QVariant(QVariant::ByteArray);
c1 = qdata.toLocal8Bit();
query.prepare("insert into tbbinary values(?,?,?)");
query.bindValue(0,11);
query.bindValue(1,c1);
query.bindValue(2,c1);
query.exec();

通过十六进制字符串插入数据:

query.prepare("insert into tbbinary values(?,?,?)");
query.bindValue(0,12);
query.bindValue(1,"1010");//16进制字符串,比如EFEF
query.bindValue(2,"1010");
query.exec();
  • 二进制类型查询
QSqlQuery query;
query.prepare("select * from tbbinary");
query.exec();
while(query.next())
{
    qDebug()<<query.value(0).toInt();
    qDebug()<<query.value(1).toString(); //将二进制转换成字符串
    qDebug()<<query.value(2).toString();//将二进制转换成字符串
}

日期类型操作

演示向数据库中的date、time、timestamp类型插入数据和读取数据的方式:

  • 日期类型插入

插入日期类型有两种方式,一种为直接插入字符串,另外一种为插入对于的QT类型,比如:

//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))");

//1) 字符串方式插入时间
query.prepare("insert into tbtime values(?,?,?,?)");
query.bindValue(0,11);
query.bindValue(1,"2020-2-6");
query.bindValue(2,"18:10:10.1");
query.bindValue(3,"2020-2-6 18:10:10.11");
query.exec();


//2) 通过QT 的时间类class插入, 支持毫秒数为3位,最大值为999
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();
  • 日期类型查询
query.prepare("select * from tbtime");
query.exec();
while(query.next())
{
    qDebug()<<query.value(0).toInt();
    qDebug()<<query.value(1).toDate().toString("yyyy-MM-dd");
    qDebug()<<query.value(2).toTime().toString("hh:mm:ss.zzz");
    qDebug()<<query.value(3).toDateTime().toString("yyyy-MM-dd hh:mm:ss");
}

bool类型操作

Binary和varbinary二进制类型,操作如下:

  • bool类型插入

插入bool类型有两种方式,一种为插入0/1数值,另外一种为插入bool值;

//create table tbbool( a int,b bool);
QSqlQuery query;
query.exec("truncate table tbbool");
query.prepare("insert into tbbool values(?,?)");

query.bindValue(0,11);
query.bindValue(1,1); //真
query.exec();

query.bindValue(0,13);
query.bindValue(1,true);  // 真
query.exec();

query.bindValue(0,14);
query.bindValue(1,0); //假
query.exec();

query.bindValue(0,15);
query.bindValue(1,false); //假
query.exec();
  • bool类型查询
QSqlQuery query;
query.prepare("select * from tbbool");
query.exec();
while(query.next())
{
    qDebug()<<query.value(0).toInt();
    qDebug()<<query.value(1).toBool(); //打印true/false
}

BLOB大对象类型操作

  • blob类型插入
//插入大约1M数据
//create table tbblob( a int,b blob);
QSqlQuery query;
QString qdata = "";
QVariant c1 = QVariant(QVariant::ByteArray);
QByteArray tmpblob = qdata.toLocal8Bit();
for(int i=1;i<=100000;i++)
 {
    tmpblob.append("1234567890");
 }
query.prepare("insert into tbblob values(?,?)");
query.bindValue(0,11);
query.bindValue(1,tmpblob);

query.exec();
  • blob类型查询
QSqlQuery query;
query.prepare("select * from tbblob");
query.exec();
while(query.next())
{
    qDebug()<<query.value(0).toInt();
    qDebug()<<query.value(1).toByteArray().size(); //打印获取到的数值长度
}

CLOB大对象类型操作

  • clob类型插入
//插入大约1M数据
//create table tbclob( a int,b clob);
QSqlQuery query;
QString qdata = "";
 for(int i=1;i<=100000;i++)
 {
    qdata.append("1234567890");
 }
query.prepare("insert into tbclob values(?,?)");
query.bindValue(0,11);
query.bindValue(1,qdata);
query.exec();
  • clob类型查询
QSqlQuery query;
query.prepare("select * from tbclob");
query.exec();
while(query.next())
{
    qDebug()<<query.value(0).toInt();
    qDebug()<<query.value(1).toString().left(10); //打印获取到CLOB数据的前10个字符
}

interval类型操作

interval时间类型因为QT中并没有类型与之对应,因此只能用字符串方式进行操作,如下:

  • interval类型插入
//create table tbinterval( a int,b INTERVAL day to second(3),c INTERVAL year to month);
QSqlQuery query;
query.exec("drop table tbinterval");
query.exec("create table tbinterval( a int,b INTERVAL day to second(3),c INTERVAL year to month)");
query.prepare("insert into tbinterval values(?,?,?)");
query.bindValue(0,11);
query.bindValue(1,"1 10:11:12.333");
query.bindValue(2,"11-10");
query.exec();
  • interval类型查询
query.prepare("select * from tbinterval");
query.exec();
while(query.next())
{
    qDebug()<<query.value(0).toInt();
    qDebug()<<query.value(1).toString();
    qDebug()<<query.value(2).toString();
}

示例代码

下面给出一段连接代码,请参考使用:

#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QDebug>
#include<QVariant>
#include<stdio.h>
#include<iostream>
#include<QTextCodec>
using namespace std;
int main()
{
     QTextCodec *codec = QTextCodec::codecForName("UTF-8");
     QTextCodec::setCodecForLocale(codec);
     QTextCodec::setCodecForCStrings(codec);
     QTextCodec::setCodecForTr(codec);
     QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");

    db.setDatabaseName("ST");
    db.setUserName("SYSDBA");
    db.setPassword("szoscar55");
    if (!db.open()) {
        printf("数据库链接失败!\n");
        return false;
    }
    printf("数据库链接成功!\n");
    //插入
    QSqlQuery query;
    query.exec("drop table testst ");
    query.exec("create table testst (id int primary key, "
              "firstname varchar(20), lastname varchar(20))");
    query.exec("insert into testst values(1, '张三', 'san')");
    //查询
    query.exec("select firstname,lastname from testst where id=1;");
    while(query.next()){
        QString name=query.value(0).toString();
        qDebug()<<name;
    }
    query.first();
    QList<QVariant> list = query.boundValues().values();
    for (int i = 0; i < list.size(); ++i)
        cout << i << ": " << list.at(i).toString().toAscii().data() << endl;
    //更新
   query.exec("update testst set lastname='wangwu' where id =1;");
    //删除
//    query.exec("delete from testst where id=1;");
    QSqlRecord rec = db.record("testst");
    if (rec.count() == 0) {
        cout << "Unable to find the table testst" << endl;
        printf("ERROR!\n");
    }
    printf("SUCCESS!\n");
   qDebug() << "column num is:" << rec.count() << endl;
db.close();
}