网站首页 > 技术文章 正文
QtSql模块
Qt提供的QtSql模块实现了对数据库的访问,同时提供了一套与平台和具体所用数据库均无关的调用接口。此模块为不同层次的用户提供了不同的丰富的数据库操作类。例如,对于习惯使用SQL语法的用户,QSqlQuery类提供了直接执行任意SQL语句并处理返回结果的方法;而对于习惯使用较高层数据库接口以避免使用SQL语句的用户,QSqlTableModel和QSqlRelationalTableModel类则提供了合适的抽象。
除此之外,此模型还支持常用的数据库模式,如主从视图(master-detail views)和向下钻取(drill-down)模式。
这个模块由不同Qt类支撑的三部分组成,QtSql模块层次结构见下表。
QtSql模块层次结构
层 次 | 描 述 |
驱动层 | 实现了特定数据库与SQL接口的底层桥接,包括的支持类有QSqlDriver、QSqlDriverCreator<T>、QSqlDriverCreatorBase、QSqlDriverPlugin和QSqlResult |
SQL接口层 | QSqlDatabase类提供了数据库访问、数据库连接操作,QSqlQuery类提供了与数据库的交互操作,其他支持类有QSqlError、QSqlField、QSqlTableModel和QSqlRecord |
用户接口层 | 提供从数据库数据到用于数据表示的窗体的映射,包括的支持类有QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel,这些类均依据Qt的模型概图结构设计 |
SQLite数据库
项目中通常采用各种数据库(如Oracle、SQLServer、MySQL等)来实现对数据的存储、检索等功能。这些数据库除提供基本的查询、删除和添加等功能外,还提供很多高级特性,如触发器、存储过程、数据备份恢复和全文检索功能等。但实际上,很多应用仅利用了这些数据库的基本特性,而且在某些特殊场合的应用中,这些数据库明显有些臃肿。
Qt提供了一种进程内数据库SQLite。它小巧灵活,无须额外安装配置且支持大部分ANSI SQL-92标准,是一个轻量级的数据库,概括起来具有以下优点。
- (1) SQLite的设计目的是实现嵌入式SQL数据库引擎,它基于纯C语言代码,已经应用在非常广泛的领域内。
- (2) SQLite在需要持久存储时可以直接读写硬盘上的数据文件,在无须持久存储时也可以将整个数据库置于内存中,两者均不需要额外的服务器端进程,即SQLite是无须独立运行的数据库引擎。
- (3) 开放源代码,整套代码少于3万行,有良好的注释和90%以上的测试覆盖率。
- (4) 少于250KB的内存占用容量(gcc编译情况下)。
- (5) 支持视图、触发器和事务,支持嵌套SQL功能。
- (6) 提供虚拟机用于处理SQL语句。
- (7) 不需要配置,不需要安装,也不需要管理员。
- (8) 支持大部分ANSI SQL-92标准。
- (9) 大部分应用的速度比目前常见的客户端/服务器结构的数据库快。
- (10) 编程接口简单易用。
在持久存储的情况下,一个完整的数据库对应于磁盘上的一个文件,它是一种具备基本数据库特性的数据文件,同一个数据文件可以在不同机器上使用,可以在不同字节序的机器间自由共享;最大支持2TB数据容量,而且性能仅受限于系统的可用内存;没有其他依赖,可以应用于多种操作系统平台。
控制台方式操作实例
基于控制台的程序,使用SQLite数据库完成大批量数据的增加、删除、更新和査询操作并输出。
操作步骤如下。
(1) 在“QSQLiteEx.pro”文件中添加如下语句:
QT += sql
QT += core
(2) 源文件“main.cpp”的具体代码如下:
#include <QCoreApplication>
#include <QTextCodec>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QTime>
#include <QSqlError>
#include <QtDebug>
#include <QSqlDriver>
#include <QSqlRecord>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTextCodec::setCodecForLocale(QTextCodec::codecForLocale()); //设置中文显示
QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE"); // (a)
db.setHostName("myNoteBook"); //设置数据库主机名
db.setDatabaseName("qtDB.db"); // (b)
db.setUserName("casaries"); //设置数据库用户名
db.setPassword("123456"); // 设置数据库密码
db.open(); // 打开连接
//创建数据库表
QSqlQuery query; //(c)
bool success = query.exec(QString("create table automobile "
"(id int primary key,"
"attribute varchar,"
"type varchar,"
"kind varchar,"
"nation int,"
"carnumBer int,"
"elevaltor int,"
"distance int,"
"oil int,"
"temperature int)")); // (d)
if(success)
qDebug()<<QObject::tr("数据库表创建成功!\n");
else
qDebug()<<QObject::tr("数据库表创建失败!\n");
//查询
query.exec("select * from automobile");
QSqlRecord rec = query.record();
qDebug()<<QObject::tr("automobile 表字段数:")<<rec.count();
//插入记录
QTime t = QTime::currentTime(); //创建一个计时器,统计操作耗时
query.prepare("insert into automobile values(?,?,?,?,?,?,?,?,?,?)"); // (e)
long records=100; // 向表中插入任意的100条记录
for(int i=0;i<records;i++){
query.bindValue(0,i); // (f)
query.bindValue(1,"四轮");
query.bindValue(2,"轿车");
query.bindValue(3,"富康");
query.bindValue(4,rand()%100);
query.bindValue(5,rand()%10000);
query.bindValue(6,rand()%300);
query.bindValue(7,rand()%200000);
query.bindValue(8,rand()%52);
query.bindValue(9,rand()%100);
success=query.exec(); // (g)
if(!success){
QSqlError lastError=query.lastError();
qDebug()<<lastError.driverText()<<QString(QObject::tr("插入失败"));
}
}
QTime curtime = QTime::currentTime();
qDebug()<<QObject::tr("插入 %1 条记录,耗时:%2 ms").arg(records).arg(0-curtime.msecsTo(t)); //(h)
//排序
t = curtime; //重新开始计时
success = query.exec ("select * from automobile order by id desc"); //(i)
curtime = QTime::currentTime();
if (success)
qDebug()<<QObject::tr("排序 %1 条记录,耗时:%2 ms").arg(records).arg(0-curtime.msecsTo(t));//输出操作耗时
else
qDebug()<<QObject::tr("排序失败! ");
//更新记录
t = curtime; //重新开始计时
for (int i = 0;i < records;i++){
query.clear();
query.prepare(QString("update automobile set "
"attribute=?,type=?,"
"kind=?,nation=?,"
"carnumber=?,elevaltor=?,"
"distance=?,oil=?,"
"temperature=? where id=%1").arg(i)); //(j)
query.bindValue(0,"四轮");
query.bindValue(1,"轿车");
query.bindValue(2,"富康");
query.bindValue(3,rand()%100);
query.bindValue(4,rand()%10000);
query.bindValue(5,rand()%300);
query.bindValue(6,rand()%200000);
query.bindValue(7,rand()%52);
query.bindValue(8,rand()%100);
success = query.exec();
if(!success){
QSqlError lastError = query.lastError();
qDebug()<<lastError.driverText()<<QString(QObject::tr("更新失败"));
}
}
curtime = QTime::currentTime();
qDebug()<<QObject::tr("更新 %1 条记录,耗时:%2 ms").arg(records).arg(0 - curtime.msecsTo(t));
//删除
t = curtime; //重新开始计时
query.exec("delete from automobile where id=15");//(k)
curtime = QTime::currentTime();
//输出操作耗时
qDebug()<<QObject::tr("删除一条记录,耗时:%1 ms").arg (0 - curtime.msecsTo(t));
return 0;
}
其中,
- (a) QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE"):以“QSQLITE”为数据库类型,在本进程地址空间内创建一个SQLite数据库。此处涉及的知识点有以下两点。
① 在进行数据库操作之前,必须首先建立与数据库的连接。数据库连接由任意字符串标识。在没有指定连接的情况下,QSqlDatabase可以提供默认连接供Qt其他的SQL类使用。建立一条数据库连接的代码如下:
QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE"); // (a)
db.setHostName("myNoteBook"); //设置数据库主机名
db.setDatabaseName("qtDB.db"); // (b)
db.setUserName("FutureRaider"); //设置数据库用户名
db.setPassword("123456"); // 设置数据库密码
db.open(); // 打开连接
其中,静态函数QSqlDatabase::addDatabase()返回一条新建立的数据库连接,其原型为:
QSqlDatabase QSqlDatabase::addDatabase(const QString &type, const QString &connectionName = QLatin1String(defaultConnection))
*参数type为驱动名,本例使用的是QSQLITE驱动。
*参数connectionName为连接名,默认值为默认连接。如果没有指定此参数,则新建立的数据库连接将成为本程序的默认连接,并且可以被后续不带参数的函数database()引用。如果指定了此参数(连接名),则函数database(connectionName)将获取这个指定的数据库连接。
② QtSql模块使用驱动插件(driver plugins)与不同的数据库接口通信。由于QtSql模块的应用程序接口是与具体数据库无关的,所以所有与数据库相关的代码均包含在这些驱动插件中。目前,Qt支持的数据库驱动插件见下表。由于版权的限制,开源版Qt不提供上述全部驱动,所以配置Qt时,可以选择将SQL驱动内置于Qt中或编译成插件。如果Qt中支持的驱动不能满足要求,还可以参照Qt的源代码编写数据库驱动。
Qt支持的数据库驱动插件
驱 动 | 数据库管理系统 |
QDB2 | IBM DB2及其以上版本 |
QIBASE | Borland InterBase |
QMYSQL | MySQL |
QOCI | Oracle Call Interface Driver |
QODBC | Open Database Connectivity(ODBC)包括Microsoft SQL Server和其他ODBC 兼容数据库 |
QPSQL | PostgreSQL版本6.x和7.x |
QSQLITE | SQLite版本3及以上版本 |
QSQLITE2 | SQLite版本2 |
QTDS | Sybase Adaptive Server |
- (b) db.setDatabaseName("qtDB.db"):以上创建的数据库以“qtDB.db”为数据库名。它是SQLite在建立内存数据库时唯一可用的名字。
- (c) QSqlQuery query:创建QSqlQuery对象。QtSql模块中的QSqlQuery类提供了一个执行SQL语句的接口,并且可以遍历执行的返回结果集。除QSqlQuery类外,Qt还提供了三种用于访问数据库的高层类,即QSqlQueryModel、QSqlTableModel和QSqlRelationTableModel。它们无须使用SQL语句就可以进行数据库操作,而且可以很容易地将结果在表格中表示出来。访问数据库的高层类见下表。
访问数据库的高层类
类 名 | 用 途 |
QSqlQueryModel | 基于任意SQL语句的只读模型 |
QSqlTableModel | 基于单个表的读写模型 |
QSqlRelationalTableModel | QSqlTableModel的子类,增加了外键支持 |
这三个类均从QAbstractTableModel类继承,在不涉及数据的图形表示时可以单独使用以进行数据库操作,也可以作为数据源将数据库内的数据在QListView或QTableView等基于视图模式的Qt类中表示出来。使用它们的另一个好处是,程序员很容易在编程时采用不同的数据源。例如,假设起初打算使用数据库存储数据并使用了QSqlTableModel类,后因需求变化决定改用XML文件存储数据,程序员此时要做的仅是更换数据模型类。
QSqlRelationalTableModel类是对QSqlTableModel类的扩展,它提供了对外键的支持。外键是一张表中的某个字段与另一张表中的主键间的一一映射。
在此,一旦数据库连接建立后,就可以使用QSqlQuery执行底层数据库支持的SQL语句,此方法所要做的仅是创建一个QSqlQuery对象,然后再调用QSqlQuery::exec()函数。
- (d) bool success = query.exec(QString("create table automobile … ")):创建数据库表“automobile”,该表具有10个字段。在执行exec()函数调用后,就可以操作返回的结果了。
- (e) query.prepare("insert into automobile values(?,?,?,?,?,?,?,?,?,?)"):如果要插入多条记录,或者避免将值转换为字符串(即正确地转义),则可以首先调用prepare()函数指定一个包含占位符的query,然后绑定要插入的值。Qt对所有数据库均可以支持Oracle类型的占位符和ODBC类型的占位符。此处使用了ODBC类型的定位占位符。
占位符通常使用包含non-ASCII字符或非non-Latin-1字符的二进制数据和字符串。无论数据库是否支持Unicode编码,Qt在后台均使用Unicode字符。对于不支持Unicode编码的数据库,Qt将进行隐式的字符串编码转换。
- (f) query.bindValue(0,i):调用bindValue()或addBindValue()函数数绑定要插入的值。
- (g) success=query.exec():调用exec()函数在query中插入对应的值,之后,可以继续调用bindValue()或addBindValue()函数绑定新值,然后再次调用exec()函数在query中插入新值。
- (h) qDebug()<<QObject::tr("插入 %1 条记录,耗时:%2 ms").arg(records).arg(0-curtime.msecsTo(t)):向表中插入任意的100条记录,操作成功后输出操作消耗的时间。
- (i) success = query.exec ("select * from automobile order by id desc"):按id字段的降序将查询表中刚刚插入的100条记录进行排序。
- (j) query.prepare(QString("update automobile set …")):更新操作与插入操作类似,只是使用的SQL语句不同。
- (k) query.exec("delete from automobile where id=15"):执行删除id为15的记录的操作。
(3) 运行结果如下图所示。
———————————————
觉得有用的话请关注点赞,谢谢您的支持!
对于本系列文章相关示例完整代码有需要的朋友,可关注并在评论区留言!
猜你喜欢
- 2024-10-20 Qt 开发经验总结 qt软件开发
- 2024-10-20 Qt QTableWidget用法总结 qtablewidget qtableview
- 2024-10-20 实战PyQt5: 068-MV框架中的项视图部件
- 2024-10-20 Qt开发经验小技巧231-235 qt开发入门简介
- 2024-10-20 Python+PyQt5进阶(5) pyqt5 django
- 2024-10-20 Qt项目升级到Qt6经验总结 qt更新界面
- 2024-10-20 QTableWidget表格中增删数据 qtablewidget清空表格
- 2024-10-20 C/C++ Qt StatusBar 底部状态栏应用
- 2024-10-20 Qt的常用控件 qt控件详解
- 2024-10-20 Python PyQt5通过QTableWidget表格控件操作SQLite数据库
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)