数据库相关类
类名 | 描述 |
---|---|
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视图类中呈现数据库中的数据变得简单.