QtSQL学习笔记(3)- 执行SQL语句
QSqlQuery类提供了一个用于执行SQL语句和浏览查询的结果集的接口。
QSqlQueryModel和QSqlTableModel类提供了一个用于访问数据库的高级接口,这将在下一节介绍。如果你不熟悉SQL,你可以直接使用下一节介绍的高级接口类。
1 执行一个查询
要执行一个SQL语句,简单的创建一个QSqlQuery对象,然后调用QSqlQuery::exec()方法即可,如下所示:
QSqlQuery query;
query.exec("SELECT name, salary FROM employee WHERE salary > 50000");
QSqlQuery的构造函数接受一个可选的QSqlDatabase对象参数,用来指定将使用哪一个数据库连接。在上面的例子中,我们并没有指定任何连接,因此使用默认连接。如果执行查询时出错,exec()将返回false,错误原因可以通过QSqlQuery::lastError()查看。
2 浏览查询结果
QSqlQuery提供了一个访问一条查询结果记录的方法。在调用了exec()方法之后,QSqlQuery的内部指针定位到了第一条记录之前的位置。我们必须调用一次QSqlQuery::next()内部指针就移动到第一条记录上,然后重复调用next()方法就可以移动到其他记录上,直到该函数返回false为止。下面给出一个典型的循环依次遍历所有的记录:
while (query.next()) {
QString name = query.value().toString();
int salary = query.value().toInt();
qDebug() << name << salary;
}
QSqlQuery::value()函数返回当前记录的一个字段值。字段的索引号从0开始计数。QSqlQuery::value()返回一个QVariant,这个类型可以保存各种C++和核心的Qt数据类型,比如int, QString和QByteArray等。不同的数据库类型将自动地映射到最近的Qt等价类型。在上面的代码中,我们使用了QVariant::toString()和QVariant::toInt()将变量类型转换为了QString和int。
补充:关于value()方法的参数-索引号的取值范围问题,我们只知道第一个字段对应的索引号为0,但是并不知道最后一个字段的索引号的时候,我们可以遍历所有可能值,由于当value()函数的索引号非法时,会返回一个非法的QVariant变量,因此,我们可以通过判断返回的QVariant变量的合法性来得知是否已经到了最后一个字段。下面给出一段示例代码:
while (query.next()){
int i = ;
QString result;
QVariant temp;
while ((temp = query.value(i++)).isValid()){
result += temp.toString();
result += " | ";
}
ui->textBrowser->append(result);
}
下面给出一个MYSQL与Qt支持的数据类型之间的转换关系表:

SQLITE3与Qt支持的数据类型之间的转换关系表如下:

你可以使用QSqlQuery::next(),QSqlQuery::previous(), QSqlQuery::first()和QSqlQuery::last()来前后移动指向记录位置的指针。可以使用QSqlQuery::at()返回当前行的索引号,如果对应的数据库支持,可以使用QSqlQuery::size()返回查询结果集的总的行数(MYSQL是支持的)。
要验证一个数据库驱动是否支持某一个特性,QSqlDriver::hasFeature()。下面的示例我们调用调用QSqlQuery::size()来检查底层的数据库是否支持此特性,否则,我们只能浏览到最后一条记录,利用查询的位置来得到查询结果中一共有多少条记录。
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 {
// this can be very slow
query.last();
numRows = query.at() + ;
}
如果你在遍历查询结果集的时候只使用正值参数的next()和seek(),你可以在调用exec()之前调用QSqlQuery::setForwartOnly(true)。当你在操作大量结果集的时候,这是一个简单的优化单可以明显加速你的查询。
3 插入、更新和删除记录
QSqlQuery可以执行任意的SQL语句。下面的示例展示了使用INSERT语句向表中插入一条记录:
QSqlQuery query;
query.exec("INSERT INTO employee (id, name, salary) "
"VALUES (1001, 'Thad Beaumont', 65000)");
如果你想要同时插入许多条记录,一个有效的方法就是将查询语句和真实的值分离,这个可以使用占位符来实现。Qt支持两种占位符:名称绑定和位置绑定。下面是一个名称绑定的示例:
QSqlQuery query;
query.prepare("INSERT INTO employee (id, name, salary) "
"VALUES (:id, :name, :salary)");
query.bindValue(":id", );
query.bindValue(":name", "Thad Beaumont");
query.bindValue(":salary", );
query.exec();
下面的代码时位置绑定的示例:
QSqlQuery query;
query.prepare("INSERT INTO employee (id, name, salary) "
"VALUES (?, ?, ?)");
query.addBindValue();
query.addBindValue("Thad Beaumont");
query.addBindValue();
query.exec();
这两种语句对于Qt提供的所有数据库驱动都支持。当需要插入多条记录时,只需要调用 一次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");
4 事务
如果底层的数据库引擎支持事务,那么QSqlDriver::hasFeature(QSqlDriver::Transactions)会返回true。可以使用QSqlDatabase::transaction()启动一个事务,然后编写一些希望在事务中执行的SQL语句,最后调用QSqlDatabase::commit()或者QSqlDatabase::rollback()。当使用事务时必须在创建查询以前就开始事务,例如:
QSqlDatabase::database().transaction();
QSqlQuery query;
query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'");
if (query.next()) {
int employeeId = query.value().toInt();
query.exec("INSERT INTO project (id, name, ownerid) "
"VALUES (201, 'Manhattan Project', "
+ QString::number(employeeId) + ')');
}
QSqlDatabase::database().commit();
事务可以保证一个复杂操作的原子性,就是对于一个数据库操作序列,这些操作要么全部做完,要么一条也不做,它是一个不可分割的工作单位。
QtSQL学习笔记(3)- 执行SQL语句的更多相关文章
- SQL学习笔记:基础SQL语句
目录 语句特点 进入数据库 基本查询语句 SELECT DISTINCT WHERE AND/OR/NOT :逻辑运算符 ORDER BY :排序 基本修改语句 INSERT:添加语句 UPDATE: ...
- Ibatis学习总结7--SqlMapClient 执行 SQL 语句
SqlMapCient 类提供了执行所有 mapped statement 的 API.这些方法如下: public int insert(String statementName, Object p ...
- CUBRID学习笔记 28 执行sql脚本文件
一下命令在csql下执行. insert_commands.sql为sql脚本文件 ;CL ;READ insert_commands.sql ;RU 第一行的cl 清空命令缓存,等同clear第二行 ...
- 吴裕雄--天生自然ORACLE数据库学习笔记:优化SQL语句
create or replace procedure trun_table(table_deleted in varchar2) as --创建一个存储过程,传入一个表示表名称的参数,实现清空指定的 ...
- 10.1(java学习笔记)JDBC基本操作(连接,执行SQL语句,获取结果集)
一.JDBC JDBC的全称是java database connection java数据库连接. 在java中需要对数据库进行一系列的操作,这时就需要使用JDBC. sun公司制定了关于数据库操作 ...
- SQL反模式学习笔记18 减少SQL查询数据,避免使用一条SQL语句解决复杂问题
目标:减少SQL查询数据,避免使用一条SQL语句解决复杂问题 反模式:视图使用一步操作,单个SQL语句解决复杂问题 使用一个查询来获得所有结果的最常见后果就是产生了一个笛卡尔积.导致查询性能降低. 如 ...
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
目录(?)[-] 二SQL语句映射文件2增删改查参数缓存 select insert updatedelete sql parameters 基本类型参数 Java实体类型参数 Map参数 多参数的实 ...
- MyBatis学习 之 二、SQL语句映射文件(1)resultMap
目录(?)[-] 二SQL语句映射文件1resultMap resultMap idresult constructor association联合 使用select实现联合 使用resultMap实 ...
- SQL*PLUS中批量执行SQL语句
SQL*PLUS中批量执行SQL语句 今天由于工作的需要,要在CMD中批量执行大量的SQL语句,对于Oracle学习还处在入门阶段的我,只能硬着头皮到处去寻找资料(主要是网络资料,也包括自己的电子书) ...
随机推荐
- 【38】通过复合塑模出Has-A 或根据某物实现出
1.什么是复合? 复合是类型之间的一种关系,某种类型的对象内含其他类型的对象. 2.为什么需要复合,他解决什么问题? 为了代码复用. 3.复合有两层含义:Has-A和根据某物实现出.在应用域中,表示H ...
- web工作方式,浏览网页,打开浏览器,输入网址按下回车键,然后会显示出内容,这个过程是怎样的呢?
以下内容摘自<Go Web编程>,介绍的通俗易懂. 我们平时浏览网页的时候,会打开浏览器,输入网址后按下回车键,然后就会显示出你想要浏览的内容.在这个看似简单的用户行为背后,到底隐藏了些什 ...
- BZOJ 2257: [Jsoi2009]瓶子和燃料 裴蜀定理
2257: [Jsoi2009]瓶子和燃料 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/p ...
- 获取windows版本信息
procedure TForm1.Button1Click(Sender: TObject); Var OSVI:OSVERSIONINFO; begin OSVI.dwOSversi ...
- spring mvc+ajax分页
分页大致思路:页面每次把当前页传到后台并获得从后台传过来的json数据,解析后布局到这个页面上. 1.服务端代码: @Controller public class MemcachedContrlle ...
- [Effective C++ --011]在operator=中处理“自我赋值”
一.何谓“自我赋值”? 1.1.场合一 直接赋值 w = w; 1.2.场合二 同一数组 a[i] = a[j]: 1.3.场合三 指针 *px = *py: 1.4. ...
- vb.net写的odbc连接dsn数据源和ole链接oracle的小例子
最近由于工作需要开始接触vb2010,也叫vb.net.相比vb6.0有面向对象编程的优势.同时接触一门新语言,要更快的实际应用起来,链接数据库是必不可少的.之前用vba写过一个售书工具,正好可以拿来 ...
- VirtualBox中centos网络配置
VirtualBox图形界面下有四种网络接入方式,它们分别是: 1.NAT 网络地址转换模式(NAT,Network Address Translation) 2.Bridged Adapter 桥接 ...
- posix thread内存可视性
线程间的内存可视性 当线程调用怕thread——create时, 它所能看到的内存值也是它建立的线程能够看到的.任何在调用怕thread_create之后写入的数据,可能不会被建立的线程看到,即使写操 ...
- 关于SWT中的布局Layout
组件装在容器里,那么这些组件是如何布局的呢?在这之前所有的例子都是使用setBounds来 进行绝对坐标的定位的. 在实际应用过程中大都是采用布局管理器的方式来布局容器中的组件. 布局管理器定义了组件 ...