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 单个数据库表的可编辑数据模型

数据库相关类分为三个层次:

  • 驱动层:
    QSqlDriver,QSqlDriverCreator,QSqlDriverCreatorBase,QSqlDriverPlugin,QSqlResult.此层次为特定数据库和SQL API之间提供了低级的沟通桥梁.
  • SQL API层:
    QSqlDatabase,QSqlQuery,QSqlError,QSqlField,QSqlIndex,QSqlRecord.此层此提供对数据库的访问.
  • 用户界面层:
    QSqlQueryModel, QSqlTableModel, QSqlRelationalTableModel.此层次将数据从数据库显示在widget上,要配合Qt的 model/view框架使用.

连接到数据库

在访问数据库之前需要先创建并打开一个或多个数据库链接.数据库链接由链接名称来区分,不由数据库名称区分.同一个数据库上可以有多个数据库链接.
注意创建链接和打开链接的区别:创建链接涉及到QSqlDatabase的实例化.连接在打开之前是不可用的,需要调用open()函数来打开它.

QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("bigblue");
db.setDatabaseName("flightdb");
db.setUserName("acarlson");
db.setPassword("1uTbSbAs");
bool ok = db.open();

第一句创建链接,最后一句打开链接,中间语句设置链接的各种参数,包括主机名,数据库名,数据库用户名,数据库密码等.第一句中的参数"QMYSQL"指明我们使用MySQL数据库,链接名称为空(默认链接).
如果发生错误请使用QSqlDatabase::lastError()来获取错误信息.
使用QSqlDatabase::database()来获取已经创建的链接.
要删除一个数据库链接,先调用close()再调用removeDatabase().

SQL数据库驱动

Qt SQL模块使用驱动插件来和不同的数据库API进行通讯.因为Qt SQL模块API是"数据库独立的",所有的数据库特异化操作代码都被包含在各自对应的驱动中.Qt SQL模块已经支持一些驱动了,并且你也可以自己添加数据库驱动.下表为已经支持的驱动:

驱动名称 描述
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 Note: obsolete from Qt 4.7

执行SQL语句

QSqlQuery类为执行SQL语句和遍历执行结果集提供了接口.

QSqlQuery query;
query.exec("SELECT name, salary FROM employee WHERE salary > 50000");

QSqlQuery的构造函数可以接收一个QSqlDatabase对象,以此来指定SQL语句要使用的数据库链接.如果没有提供QSqlDatabase对象,SQL语句会在默认链接上执行.如果有错误exec()函数会返回fasle.使用QSqlQuery::laseError()获取错误信息.

遍历结果集合:

QSqlQuery允许每次访问一条结果集中的记录.调用exec()函数后QSqlQuery的内部指针位于第一个记录的前一个位置,在访问第一条记录之前必须要调用QSqlQuery::next(),依次重复知道next()函数返回值为false.

 while (query.next()) {
        QString name = query.value(0).toString();
        int salary = query.value(1).toInt();
        qDebug() << name << salary;
 }

QSqlQuery::value() 返回当前记录中的字段值,返回值是QVariant类型的.
结果集合遍历函数列表:

函数名称 描述
QSqlQuery::next() 下一条记录
QSqlQuery::previous() 上一条记录
QSqlQuery::first() 第一条记录
QSqlQuery::last() 最后一条记录
QSqlQuery::seek() 跳到指定记录
QSqlQuery::at() 当前记录索引
QSqlQuery::size() 总记录条数
QSqlDriver::hasFeature() 当前类型的数据库是否支持某种操作特性
QSqlQuery query;
int numRows;
query.exec("SELECT name,salary FROM employee WHERE salary > 50000");

QSqlDatabase defaultDB = QSqlDatabase::database();
if(defaultDB.driver()->hasFeature(QSqlDriver::QuerySize))
{
    numRows = query.size;
}
else
{
    query.last();
    numRows = query.at()+1;
}

如果仅使用next()和seek()的正值进行迭代,则可以在调用exec()之前调用QSqlQuery :: setForwardOnly(true). 这是一个简单的优化,可以加快大型结果集上的查询速度。

插入,更新,删除记录

QSqlQuery可执行任意的SQL语句,而不止SELECT语句.

插入示例

QSqlQuery query;
query.exec("INSERT INTO employee(id,name,salary) "
                  "VALUES (1001,'Thad Beaumont',65000)");

如果希望插入多条记录,将SQL语句和实际要插入的值分开来写是更高效的,这可以使用占位符来实现,Qt支持两种格式的占位符,名称绑定和位置绑定.

  • 名称绑定示例
QSqlQuery query;
query.prepare("INSERT INTO employee (id, name, salary) "
                    "VALUES (:id, :name, :salary)");
query.bindValue(":id", 1001);
query.bindValue(":name", "Thad Beaumont");
query.bindValue(":salary", 65000);
query.exec();
  • 位置绑定示例
QSqlQuery query;
query.prepare("INSERT INTO employee (id, name, salary) "
                    "VALUES (?, ?, ?)");
query.addBindValue(1001);
query.addBindValue("Thad Beaumont");
query.addBindValue(65000);
query.exec();

这两种语法适用于Qt提供的所有数据库驱动程序,如果数据库本身支持此语法,Qt将查询转发给DBMS,否则Qt会通过预处理来模拟占位符语法.最终由DBMS执行的SQL语句可以通过QSqlQuery::ecutQuery()获取.
插入多条记录时只需要调用一次QSqlQuery::prepare(),然后可以按照你的需要重复多次调用bindValue()或者addBindValue() 和exec().

更新示例

QSqlQuery query;
query.exec("UPDATE employee SET salary = 70000 WHERE id = 1003");

同样,更新时也可以使用名称或者位置占位符.

删除示例

QSqlQuery query;
query.exec("DELETE FROM employee WHERE id = 1007");

判断表是否存在

bool isTableExists(QString tableName)
{
      QSqlDatabase db = QSqlDatabase::database();          // 假设数据库连接已经成功打开
      QStringList tableList = db.tables(QSql::AllTables);
      return tableList.contains(tableName);
}

数据库事务

如果底层数据库引擎支持事务,QSqlDriver::hasFeature(QSqlDriver::Transactions)会返回true.调用QSqlDatabase::transaction()来启动事务,后面跟着你想在事务上下文中完成的SQL语句,然后执行QSqlDatabase::commit()或者QSqlDatabase::rollback().使用事务时必须要在创建query前开启事务.

QSqlDatabase::database().transaction();
QSqlQuery query;
query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'");
if (query.next()) {
    int employeeId = query.value(0).toInt();
    query.exec("INSERT INTO project (id, name, ownerid) "
               "VALUES (201, 'Manhattan Project', "
               + QString::number(employeeId) + ')');
}
QSqlDatabase::database().commit();

事务用于保证复杂的操作的原子性.

使用SQL模型类

除了QSqlQuery之外,Qt提供三个高级类来访问数据库:

类名 描述
QSqlQueryModel 基于任意SQL查询的只读模型
QSqlTableModel 单独一张表上的读写模型
QSqlRelationalTableModel 具有外键支持的QSqlTableModel

这些类继承自QAbstractTableModel(进一步继承自QAbstractItemModel),这使得在诸如QListView和QTableView视图类中呈现数据库中的数据变得简单.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容