Qt SQL编程官方教程

出处:Qt SQL Programming Guide

该概览假设你有SQL的基础知识,如select,insert,update和delete。尽管QSqlTableModel类在不需要SQL知识的情况下提供了浏览和编辑数据库的接口,但仍强烈推荐理解SQL。

话题包括:

1.Database Classes:数据库类

2.Connecting to Databases:连接到数据库

        SQL Database Drivers:SQL数据库驱动器

3.Executing SQL Statements:执行SQL语句

        Data Types for Qt-supported Database Systems:Qt支持的数据库系统的数据类型

4.Using the SQL Model Classes:使用SQL model类

5.Presenting Data in a Table View:在Table View中展示数据

6.Creating Data-Aware Forms:创建数据感知的Forms

一、Database Classes:数据库类

数据库的类

SQL类分为三层:

1)Driver层:该层为SQL API层和数据库提供桥梁。

2)SQL API层:该层提供访问数据库的接口。用 QSqlDatabase类连接数据库。用QSqlQuery类和数据库进行交互。除了上述2个类,还有 QSqlErrorQSqlFieldQSqlIndex, 和 QSqlRecord.。

3)用户接口层:该层的类把数据库里的数据连接到widget,包括 QSqlQueryModelQSqlTableModel, 和 QSqlRelationalTableModel

二、Connecting to Databases:连接到数据库

访问数据库之前,首先要创建并打开一个或多个数据库连接。数据库连接通常用 [连接名] 来标识。对同一个数据库可以有多个连接。QSqlDatabase还支 [默认连接] 的概念,它是个未命名的连接。当调用QSqlQuery或QSqlQuery的方法且其中需要[连接名]参数时,如果不传递一个[连接名],则使用[默认连接]。

当应用程序中只有一个连接时,使用默认连接是最方便的。

创建打开连接是不同的。创建一个连接是创建一个QSqlDatabase对象,但是为打开前连接是不可用的。下面的代码展示了如何创建一个连接并打开。


创建和打开连接

第一句是创建连接,最后一句是打开连接,中间是做一些准备。参数“QMYSQL”用来指定数据库驱动器的类型。Qt支持的数据库类型在supported database drivers中。

上面的代码展示的是【默认连接】,应为没有给 addDatabase()传递【连接名】。下面是两个命名的连接:


命名连接

使用 open() 函数打开连接。如果失败了,则返回false,用 QSqlDatabase::lastError() 来获取错误信息。

当连接建立后,可以在任何地方使用静态函数QSqlDatabase::database() 来获取连接,如果不传递连接名,则返回默认连接。


获取连接

想要移除连接,则先用 QSqlDatabase::close()关闭连接,然后用静态函数QSqlDatabase::removeDatabase()移除。对于默认连接,用connectionName()获得名字,然后移除。

连接的关闭和移除

三、Executing SQL Statements:执行SQL语句

QSqlQuery 类提供了执行SQL语句的接口以及获取查询结果集合的接口。

 QSqlQueryModel and QSqlTableModel 提供了访问数据库的更高层次的接口。如果你不熟悉SQL,可以直接跳转到下一节。

要执行SQL语句,简单的创建一个QSqlQuery 对象并调用 QSqlQuery::exec()函数即可。


执行SQL语句

QSqlQuery 的构造函数接收一个可选的 QSqlDatabase 对象来指定使用哪个连接。上面没有传递该参数,表明使用的是默认连接。

如果exec() 返回false,表明有错误,则调用 QSqlQuery::lastError()来查看。

如何查看查询的结果呢?QSqlQuery提供了对结果集合的访问,每次可以访问一条记录。调用exec() 后,QSqlQuery内部的指针在first record的前面,因此必须调用一次 QSqlQuery::next()来获取第一条记录,然后继续调用 QSqlQuery::next()来获取其他记录,直到返回false。

下面的代码是获取所有记录的典型循环:

遍历查询结果

 QSqlQuery::value() 返回当前记录的一个字段值。字段用zero-based的索引指定。 QSqlQuery::value()返回一个 QVariant, 该类型可以存储很多种 C++ 和 Qt 数据类型,例如 int, QString, and QByteArray

对于Qt推荐的数据类型,查看此表this table.


Qt推荐的数据类型

可以用 QSqlQuery::next(), QSqlQuery::previous(), QSqlQuery::first(), QSqlQuery::last(), 和 QSqlQuery::seek()来寻找各个记录。 QSqlQuery::at()返回当前记录所在的行号。 QSqlQuery::size() 返回查询结果集合中所有的记录个数(行数)。

 QSqlDriver::hasFeature()用来判断数据库驱动器是否支持特定的属性。


查看记录的行数

如果你只是前向浏览,在exec() 前先调用 QSqlQuery::setForwardOnly(true)能显著的加速对多结果查询。

Insert、Update和Delete记录


直接插入

除了直接插入,qt还支持命名的占位符和索引的占位符,如下所示。

命名的占位符,必须用冒号(:)开头


位置占位符

QSqlQuery::executedQuery()返回DBMS实际执行的语句,可能跟 QSqlQuery里写的不同(但作用相同)。

若果想要插入多条记录,只需要调用 QSqlQuery::prepare() 一次,然后调用 bindValue() 或 addBindValue() 紧跟着 exec() 多次。

占位符的好处除了性能,还不用担心转义字符。

Update和Delete也可以用命名或位置的占位符。

更新


删除

事务:Transaction

如果数据库支持事务,QSqlDriver::hasFeature(QSqlDriver::Transactions) 返回true. 用 QSqlDatabase::transaction() 来启动事务,然后执行SQL语句,最后用 QSqlDatabase::commit() or QSqlDatabase::rollback()来提交或回滚。当使用transaction时,必须先启动transaction然后再创建QSqlQuery,如下图所示。


提事务的开始和提交

四、Using the SQL Model Classes:使用SQL model类

除了使用接近底层的 QSqlQuery,Qt还提供了更高层次的类来访问数据库,包括 QSqlQueryModelQSqlTableModel, 和QSqlRelationalTableModel.

QSqlQueryModel可以基于多表查询,更灵活,而后两者只能基于一张表,不太灵活。

这些类都派生自 QAbstractTableModel (它又派生自 QAbstractItemModel),他们使得在View上(如QListView或QTableView)展示数据更方便。在下一节 Presenting Data in a Table View 中会讨论。

使用这些类的另一个好处是修改数据源时代码简单,例如从数据库改成xml数据。

SQL Query Model

QSqlQueryModel提供了一个基于SQL查询的只读model。

QSqlQueryModel的setQuery()和record()比较重要

当用setQuery()函数设置查询后,可以用record(int)函数获取单条记录。还可以用data()函数获取数据,也可以用继承自 QAbstractItemModel的函数。

setQuery()可以查询多个table,view等内容,很灵活。

 setQuery() 还有一个重载函数,使用 QSqlQuery 对象来实现 QSqlQuery 的所有特性,如prepare函数。

如果数据库不支持返回query size(SQLite就不支持),则rowCount()返回是的当前缓存的行数,而不一定是真实的查询行数,此时要看 canFetchMore()是否为真,然后用 fetchMore()获取更多,直到 canFetchMore()为false。


强制获取所有的查询结果

SQL Table Model

QSqlTableModel提供了一个可读可写的模型,但每次只能工作在一张table上(没有QSqlQueryModel灵活)。

QSqlTableModel的应用

QSqlTableModel 用来浏览和修改单个SQL table。

利用 QSqlTableModel::record(int)来获取表格中的一行记录,用 QSqlTableModel::setRecord() 来修改行。下面的例子是把工资提高10%。

QSqlTableModel::setRecord()的用法

修改数据后用submitAll()提交所有的待处理的改变。

还可以用 QSqlTableModel::data() 和 QSqlTableModel::setData()来访问数据,如下图所示。

用setData()访问数据

下图展示了如何向QSqlTableModel中插入一行数据insertRows(),然后设置数据内容setData(),最后提交数据库submitAll()。

用insertRows来添加记录

removeRows()来删除行,然后submitAll()提交给数据库。

删除行

当完成对记录的改变,需要调用submitAll()来把修改的数据写入到数据库中。

何时调用submitAll()取决于QSqlTableModel的edit strategy,默认的策略是QSqlTableModel::OnRowChange,就是缓存一行的数据,当用户选择其他行时,更新数据库。 QSqlTableModel::OnManualSubmit 是所有的改变都先缓存在model中,当调用submitAll()时才写数据库;QSqlTableModel::OnFieldChange 是不缓存,直接写数据库。

更新数据库的3中方式

SQL Relational Tabel Model

QSqlRelationalTableModel是对QSqlTableModel的扩展,它支持外键(foreign key),外键是另一个表的主键。

如下图所示,左边表格的(city, country)都是外键,且是数字,右边表格则把外键修改成了用户可读的内容。

外键

下图展示了 QSqlRelationalTableModel 如何设置的实例:

setRelation()函数用来设置外键,会用到 QSqlRelation对象。

外键

五、Presenting Data in a Table View:在Table View中展示数据

QSqlQueryModel,QSqlTableModel和QSqlRenationalTableModel类可以用来作为Qt View的数据源,如QListViewQTableView, 和QTreeView,其实最常用的还是 QTableView,因为SQL结果就是table。

下面是创建一个基于SQL data model的视图,使用setModel()函数:

创建view并设置model

如果model是read-write的模型(如QSqlTableModel),view允许用户编辑字段。当然也可以通过如下代码禁用:

禁用编辑

视图会显示表头,想要改变表头的文字,调用model的setHeaderData() ,默认情况下表头是数据库中table的字段头。


设置表头

QTableView 还有垂直的表头来时识别行号。如果调用 QSqlTableModel::insertRows(),新的行会显示*,直到调用 submitAll() 或用户自动提交更改( QSqlTableModel::OnRowChange)。

插入行时显示*

同样,当调用 removeRows()时,行前面会有!。

视图中的item用代理来渲染,默认的代理是QStyledItemDelegate,它可以处理绝大多数的数据类型(如int,QString,QImage等)。当用户编辑view中的item时,代理同时负责提供编辑器widget(如combobox)。你也可以创建自己的代理,子类化 QAbstractItemDelegate or QStyledItemDelegate即可。

QSqlTableModel只能操作一个table。如果你需要一个能够读写且能够处理任意查询结果的model,你可以子类化QSqlQueryModel并实现其中的flags() 和 setData() 函数来使他能够read-write. 下面两个函数能够让model查询结果的字段1和字段2可编辑。

可编辑的QureyModel

其中setFirstName()函数定义如下:

setFritrName函数

查看 Query Model 示例可以得到完整的代码。

子类化一个model可以实现很多自定义的功能:例如给每个item提供tooltips,改变背景颜色、提供计算值等等。

如果需要解决外键的显示,则可以用QSqlRelationalTableModel。推荐使用QSqlRelationalTableModel,有代理可以提供combobox对外键的编辑。

Relational Table Model示例展示了如何使用 QSqlRelationalTableModel 和 QSqlRelationalDelegate 来提供外键的支持。

六、Creating Data-Aware Forms:创建数据感知的Forms

有些时候,除了把model里的数据放到view里,还可能会放到其他widge里,比如SpinBox,comboBox,LineEditor等。

QDataWidgetMapper可以把model中的数据映射到widget中。

QDataWidgetMapper处理一个指定一个数据库table,通过行或列的形式映射数据。因此,使用QDataWidgetMapper和SQL model就像使用其他table model一样简单。

QDataWidgetMapper做映射

The Books展示了如何使用QDataWidgetMapper以及一系列输入widgets的案例。


SQLite QSqlQuery的size()方法始终返回-1

https://deepinout.com/sqlite/sqlite-questions/184_sqlite_qsqlquery_size_always_returns_1.html

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

推荐阅读更多精彩内容