Qt开发总结(28)——数据库

 

这篇总结一下Qt的数据库操作。这篇文章可能涉及一些数据库语句,我这里不做过多解释,如果您不太具备数据库知识,大概也可以看懂,实在不行,只好去补习下SQL的知识,起码把SQL语句学一下。

概述

Qt 提供了 QtSql 模块来提供平台独立的基于 SQL 的数据库操作。这里我们所说的“平台独立”,既包括操作系统平台,又包括各个数据库平台。Qt 的数据库操作还可以很方便的与 model/view 架构进行整合。通常来说,我们对数据库的操作更多地在于对数据库表的操作,而这正是 model/view 架构的长项。

要在项目中启用Qt SQL,请将此伪指令添加到C ++文件中:

  #include

要链接到Qt SQL模块,请将此行添加到项目文件中:

  QT + = SQL

数据库相关的类有:

类名

描述

QSqlDatabase

代表一个数据库链接

QSqlDriverCreator

提供特定驱动程序类型的SQL驱动程序工厂的模板类

QSqlDriverCreatorBase

QSqlDriverCreator的基类

QSqlDriver

用于访问特定SQL数据库的抽象基类

QSqlError

SQL数据库错误信息

QSqlField

处理SQL数据库表和视图中的字段

QSqlIndex

操纵和描述数据库索引的功能

QSqlQuery

执行和操纵SQL语句的方法

QSqlRecord

封装数据库记录

QSqlResult

用于从特定SQL数据库访问数据的抽象接口

QSql

包含在整个Qt SQL模块中使用的其他标识符

QSqlQueryModel

SQL结果集的只读数据模型

QSqlRelationalTableModel

具有外键支持的单个数据库表的可编辑数据模型

QSqlTableModel

单个数据库表的可编辑数据模型

从上表中可以归纳出Qt SQL支持的三个层次数据库功能:

驱动层:

QSqlDriver,QSqlDriverCreator,QSqlDriverCreatorBase,QSqlDriverPlugin,QSqlResult.此层次为特定数据库和SQL API之间提供了低级的沟通桥梁.

SQL API层:

QSqlDatabase,QSqlQuery,QSqlError,QSqlField,QSqlIndex,QSqlRecord.此层此提供对数据库的访问.

用户界面层:

QSqlQueryModel, QSqlTableModel, QSqlRelationalTableModel.此层次将数据从数据库显示在widget上,要配合Qt的 model/view框架使用.

数据库驱动支持

Qt SQL模块使用驱动程序插件(plugins)与不同的数据库API通信。由于Qt的SQL模块API与数据库无关,因此所有特定于数据库的代码都包含在这些驱动程序中。Qt本身提供了几个驱动程序,另外用户可以添加其他自定义驱动程序。为此,Qt提供了驱动程序源代码,可以将其用作编写自己的驱动程序的模型。

Qt本身已经支持的数据库驱动有:

驱动

数据库

QDB2

IBM DB2 (version 7.1 and above)

QIBASE

Borland InterBase

QMYSQL

MySQL

QOCI

Oracle Call Interface Driver

QODBC

Open Database Connectivity (ODBC) - Microsoft SQL Server and other ODBC-compliant databases

QPSQL

PostgreSQL (versions 7.3 and above)

QSQLITE2

SQLite version 2

QSQLITE

SQLite version 3

QTDS

Sybase Adaptive Server;注意: 从Qt 4.7之后不支持

用户也可以自行编译需要的数据库驱动。曾在Qt4时代,我用Qt4.6自己编译过MySQL的驱动(Qt5.9已经默认支持MySQL了)。编译的过程都类似,大家可以移步到我的另一篇博客参观:编译MySQLQt4驱动.

其核心思想就是打开驱动源码,执行qmake和nmake:

cd %QTDIR%\qtbase\src\plugins\sqldrivers

qmake -- MYSQL_INCDIR=C:/MySQL/include "MYSQL_LIBDIR=C:/MYSQL/MySQL Server /lib/opt"

nmake sub-mysql

对于Oracle数据库OCI,Qt5也需要自己编译其驱动。Qt OCI插件支持Oracle 9i,10g和更高版本。在Windows上构建OCI插件要首先从Oracle Client Installation CD中选择Oracle Client Installer中的“ Programmer”选项。对于某些版本的Oracle Client,您可能还需要选择“呼叫接口(OCI)”选项(如果有)。

cd %QTDIR%\qtbase\src\plugins\sqldrivers

qmake -- OCI_INCDIR=c:/oracle/oci/include OCI_LIBDIR=c:/oracle/oci/lib/msvc

nmake sub-oci

如果你没有使用Microsoft编译器,请在上面的行中替换nmake为mingw32-make。

如果你不确定自己的Qt支持了哪些驱动,可以用QSqlDatabase::drivers()找到系统中所有可用的数据库驱动的名字列表。

数据库操作

下面将具体以Qt操作MySQL为例总结Qt的数据库操作。

连接到数据库

QSqlDatabase负责加载和管理数据库驱动程序插件。添加数据库后(请参见QSqlDatabase :: addDatabase()),将加载相应的驱动程序插件(使用QSqlDriverPlugin)。QSqlDatabase依靠驱动程序插件为QSqlDriver和QSqlResult提供接口。所以,首先需要添加数据库引擎:

QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
//其次就是设置数据库的地址、用户、密码等信息连接它:
db.setHostName("127.0.0.1");   //数据库服务器ip
db.setUserName("root");        //数据库用户名
db.setPassword("123456");      //密码
db.setDatabaseName("info");    //使用哪个数据库
//打开数据库
if(!db.open())
{
    QMessageBox::warning(this, "错误", db.lastError().text());
    return;
}

 

增删改查

数据库的典型操作有增删改查。QSqlQuery类可以支持几乎所有的数据库语句。我们还可以通过使用QSqlQuery::isActive()函数检查语句执行正确与否。如果QSqlQuery对象是活动的,该函数返回 true。所谓“活动”,就是指该对象成功执行了exec()函数,但是还没有完成。如果需要设置为不活动的,可以使用finish()或者clear()函数,或者直接释放掉这个QSqlQuery对象。

QSqlQuery query(db);//绑定要访问的数据库
query.exec(" create table student(id int primary key auto_increment, name varchar(255), age int, score int);");

 

//插入单条数据

query.exec(" insert into student(id, name, age, score) values(1, 'mike', 18, 76);");

如果我们需要插入多条数据,此时可以使用QSqlQuery::exec()函数一条一条插入数据,但是这里我们选择了另外一种方法:批量执行。首先,我们使用QSqlQuery::prepare()函数对这条 SQL 语句进行占位符预处理,预示着以后我们可以使用实际数据替换这些位置。简单说明一下,预处理是数据库提供的一种特性,它会将 SQL 语句进行编译,性能和安全性都要优于普通的 SQL 处理。然后我们调用QSqlQuery::execBatch()批量执行 SQL,之后结束该对象。这样,插入操作便完成了。

//预处理语句:占位符: +自定义名字
query.prepare(" insert into student(name, age, score) values(:name, :age, :score);");
//给字段设置内容 list
QVariantList nameList,ageList, scoreList;
nameList << "小米" << "华为" << "三星";
ageList <<33 <<43 <<55;
scoreList << 59 << 69 << 100;
//给字段绑定(可以不按照顺序,有占位符: +自定义名字)
query.bindValue(":name",nameList);
query.bindValue(":age",ageList);
query.bindValue(":score",scoreList);
//执行预处理命令
query.execBatch();

 

查找数据即执行SQL语言中的select语句即可:

query.exec("select * from student where name = '华为'");//从表中遍历name为华为的行
while(query.next())//一行一行遍历
{
    //取出当前行的内容,取得时候按列来取
    qDebug() << query.value(0).toInt()
            << query.value(1).toString()
            << query.value("age").toInt()
            << query.value("score").toInt();
}

 

修改或叫更新数据用update语句:

query.exec("update student set score = 100 where name = '华为'");

删除用delete语句:

query.exec("delete from student where name = '华为'");

关闭数据库:

db.close();

总之,数据库的操作就是用exec执行SQL语句即可。至于SQL语句,可能不同的数据库还有些差别。在使用时要注意。

事物操作

有的应用场景需要用到数据库的事物操作。主要包括:transaction(),commit()提交,rollback()回滚。注意:操作事务前,先判断该数据库是否支持事务操作。hasFeature是QSQLDriver类函数

//插入一条记录,然后提交事务
if (QSqlDatabase::database().driver()->hasFeature(QSqlDriver::Transactions))
{
 ... 
} 
//
QSqlDatabase::database().transaction();  
QSqlQuery query;  
query.exec("SELECT * FROM T_STUDENT WHERE age=12");  
if (query.next())  
{  
    query.exec("INSERT INTO T_STUDENT (name,age,score) VALUES ('小李',13,99)");  
}  
if(!QSqlDatabase::database().commit())
{
    QMessageBox::critical(this,"Error","操作失败,将要回滚");
    if(!QSqlDatabase::database().rollback())
    {
        QMessageBox::critical(this,"Error","回滚失败");
    }
}  

模型/视图应用

Qt SQL的用户界面层提供了几个非常方便使用的类,这些类将数据从数据库链接到数据感知小部件。它们包括QSqlQueryModel,QSqlTableModel和QSqlRelationalTableModel。这些类旨在与Qt的模型/视图框架一起使用。关于Qt的模型/视图架构,我已经在模型/视图里总结过了。

这种基于QSqlTableModel 的模型处理更为高级,如果对 SQL 语句不熟悉,并且不需要很多复杂的查询,这种QSqlTableModel模型基本可以满足一般的需求。值得注意的是,QSqlTableModel并不一定非得结合 QListView或QTableView使用,我们完全可以用其作一般性处理。

连接数据库的操作依然与上面的介绍的一样,当连接成功后,我们可以通过QSqlTableModel来进行数据库操作。

model->setTable ("student");//设定表名
model->setEditStrategy (QSqlTableModel::OnManualSubmit);//所有的操作都将被缓存,直到submitAll() or revertAll()被调用.
model->select ();//选取整个表的所有行
ui->tableView->setModel (model);

使用setTable()函数设置所需要操作的表,用select()选择整个表,在用view的setModel接口即可将整个数据表显示在UI的表格中。如果想查询或显示部分,只要设置过滤器就可以了:

model.setFilter("age > 20 and age < 25");

也就是 WHERE 语句所需要的部分。例如上面代码中的操作实际相当于 SQL 语句

SELECT * FROM student WHERE age > 20 and age < 25

我们也可以通过下面的方式遍历数据:

if (model.select()) 
{
for (int i = 0; i < model.rowCount(); ++i)
{
    	QSqlRecord record = model.record(i);
    	QString name = record.value("name").toString();
    	int age = record.value("age").toInt();
    	qDebug() << name << ": " << age;
    }
}

 

使用QSqlTableModel::select()函数进行操作,也就是执行了查询操作。如果查询成功,函数返回 true,由此判断是否发生了错误。如果没有错误,我们使用record()函数取出一行记录,该记录是以QSqlRecord的形式给出的,而QSqlRecord::value()则取出一个列的实际数据值。注意,由于QSqlTableModel没有提供const_iterator遍历器,因此不能使用foreach宏进行遍历。

另外需要注意,由于QSqlTableModel只是一种高级操作,肯定没有实际 SQL 语句方便。具体来说,我们使用QSqlTableModel只能进行 SELECT * 的查询,不能只查询其中某些列的数据。

下面一段代码则显示了如何使用QSqlTableModel进行插入操作:

QSqlTableModel model;
model.setTable("student");
int row = 0;
model.insertRows(row, 1);
model.setData(model.index(row, 1), "Cheng");
model.setData(model.index(row, 2), 24);
model.setData(model.index(row, 3), 99);
model.submitAll();

 

插入也很简单:model.insertRows(row, 1);说明我们想在索引 0 的位置插入 1 行新的数据。使用setData()函数则开始准备实际需要插入的数据。注意这里我们向 row 的第一个位置写入 Cheng(通过model.index(row, 1),回忆一下,我们把 model 当作一个二维表,这个坐标相当于第 row 行第 1 列),其余以此类推。最后,调用submitAll()函数提交所有修改。这里执行的操作可以用如下 SQL 表示:

INSERT INTO student (name, age,score) VALUES ('Cheng', 24,99)

当我们取出了已经存在的数据后,对其进行修改,然后重新写入数据库,即完成了一次更新操作:

record.setValue("age", 26);
model.setRecord(0, record);
model.submitAll();
//或者:
model.setData(model.index(0, 1), 26);

 

注意我们的 age 列是第2列,索引值为 1,这里的更新操作则可以用如下 SQL 表示:

UPDATE student SET age = 26 WHERE age = 25

删除操作如下:

model.removeRows(0, 1);
model.submitAll();

这相当于:

DELETE FROM student WHERE age = 25

另外,model中还提供了排序功能:

model->setSort (0, Qt::AscendingOrder);
model->select ();

事物操作:

model->database ().transaction ();  //开始事物操作
if(model->submitAll ())
    model->database ().commit ();//提交
else
{
    model->database ().rollback ();//回滚
    QMessageBox::warning (this, tr("tableModel"), tr("数据库错误:%1").arg (model->lastError ().text ()));
}

 

撤销:

model->revertAll ();//撤销修改

例子

最后放两个例子,一是用数据库语言实现的,另一个则用模型/视图框架实现:例子

Qt开发总结(28)——数据库_第1张图片

Qt开发总结(28)——数据库_第2张图片

你可能感兴趣的:(Qt)