QT与数据库连接
2016-05-26 16:08
459 查看
QSql 模块提供了访问 SQL 数据库的接口,这些接口独立于操作系统,独立于数据库系统。Qt 中有很多支持这个接口的类,这些类型通过 Qt 的 model/view 架构将数据库与用户界面结合起来。
数据库连接由 QSqlDatabase 类对象表示,Qt 通过驱动与不同的数据库 API 通讯。Qt Desktop Edition 版本中的 drivers 包括:
QDB2,IBM DB2 7.1 以上的数据库版本
QIBASE,Borland InterBase
QMYSQL,MySQL
QOCI,Qracel
QODBC,ODBC,包括 Microsoft SQL Server
QPSQL,PostgreSQL 7.3 及以上版本
QSQLITE,SQLite 3
QSQLITE2,SQLite 2
QTDS,Sybase Adaptive Server
Qt Open Sourcee Edition 版本只提供部分 drivers。在配置 Qt 时,用户可以在 Qt 程序中包含 SQL drivers,也可以将这些 drivers 作为 glugins 构建。
注意,在开发之前,需要保证具有数据库的驱动包,如果没有需要自行编译,不过据我所知好像5.2以后就自带了好几个数据库的驱动包,可到mingw/plugins/sqldriver文件夹下查看。
QSqlDatabase::addDatabase( ) 用于创建 QSqlDatabase 对象。它的第一个参数指明了访问数据库的 driver;接下来,分别设置数据库的主机名,数据库名,用户名,密码;最后,打开数据库连接。
通常,可以在 main( ) 函数中调用 createConnection( ) :
或者直接写为:
然后可以处理查询结果:
第一次调用 query.next( ) 时,查询记录指针指向第一条记录;接下来每调用一次 next( ),指针向后移一条记录,直到指针指向记录的尾端(尾端是最后一条记录的下一个位置),这时 next( ) 返回 false。
query.value( ) 函数返回记录中某个域的值,这个返回值的类型是 QVariant。像上面的例子中,查询记录中包括两个域:title 和 year,这些域从 0 开始编号。
除了上面的一些函数,像 first( ),last( ),previous( ),seek( ) 等函数也可用于对查询结果的记录指针进行偏移操作。但是对于访问大型的数据库时,通常的方法是在调用 exec( ) 之前,调用 QSqlQuery : : setForwardOnly(true) 进行指针偏移优化,然后在操作结果记录时只使用 next( ) 进行偏移。
在使用一个创建出来的 query 前,还可以调用 isActive( ) 查看是否有错误,如果没有错误就可以用上面的函数对结果进行查询操作:
也可以使用点位符替代记录中的值:
上面的点位符是 Oracle 风格,不同的数据库管理系统有不同的点位符格式,下面的点位符具有 ODBC 风格:
执行 exec( ) 后,可以再调用 addBindValue 或者 bindValue 函数为点位符绑定新的值继续进行操作。
QSqlDatabase::database( ) 函数返回一个 QSqlDatabase 对象,这个对象是在 createConnection( ) 函数中创建的。如果交易创建失败,transaction( ) 函数将返回 false。hasFeature( ) 函数可以用来检查某个数据库是否支持交易操作:
通过传递给 database( ) driver 的名称,可以得到对应的 QSqlDatabase 对象的指针:
通过返回的 db 可以初始化执行 SQL 操作的 QSqlQuery 对象:
这个代码相当于使用 SQL :
SELECT * FROM cd WHERE year >= 2016
遍历数据库中每一个记录的方法也很直接:
其中 QSqlTableModel : : record( ) 取得一个给定的记录,value( ) 通过域名,或者是域的索引取得域值。在大型的数据库中操作时,建议用域的索引指定某个域。例如:
插入的操作也很直接,insertRow( ) 插入一行空的记录,setData( ) 则设置此行记录中每一个域值:
插入的行实际位于数据库中哪一行,取决于当前数据库记录的排序次序。如果插入失败,submitAll( ) 函数返回 false。
为了更新一条记录,首先从 QSqlTableModel 中找到该记录的位置。然后抽出记录,更新域值,再将记录写入数据库:
更新记录的另一种办法是使用 setData( ):
删除一条记录的只得类似更新操作:
这个例子中,removeRows( ) 第一个参数是得到的 model 中的第一行(以 0 索引),第二个参数是需要删除的记录条数(这里是一条)。删除所有满足条件的记录则如下:
数据库连接由 QSqlDatabase 类对象表示,Qt 通过驱动与不同的数据库 API 通讯。Qt Desktop Edition 版本中的 drivers 包括:
QDB2,IBM DB2 7.1 以上的数据库版本
QIBASE,Borland InterBase
QMYSQL,MySQL
QOCI,Qracel
QODBC,ODBC,包括 Microsoft SQL Server
QPSQL,PostgreSQL 7.3 及以上版本
QSQLITE,SQLite 3
QSQLITE2,SQLite 2
QTDS,Sybase Adaptive Server
Qt Open Sourcee Edition 版本只提供部分 drivers。在配置 Qt 时,用户可以在 Qt 程序中包含 SQL drivers,也可以将这些 drivers 作为 glugins 构建。
注意,在开发之前,需要保证具有数据库的驱动包,如果没有需要自行编译,不过据我所知好像5.2以后就自带了好几个数据库的驱动包,可到mingw/plugins/sqldriver文件夹下查看。
1. 建立数据库连接
在进行 SQL 查询之前,需要与数据库建立连接。通常,在程序执行前用户需要调用创建连接的函数以建立与数据库的连接。例如:bool createConnection( ) { QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("localhost"); db.setDatabaseName("root"); db.setUserName("swxc"); db.setPassword("****"); if (!db.open()) { QMessageBox::critical(0, QObject::tr("Database Error"), db.lastError().text()); return false; } return true; }
QSqlDatabase::addDatabase( ) 用于创建 QSqlDatabase 对象。它的第一个参数指明了访问数据库的 driver;接下来,分别设置数据库的主机名,数据库名,用户名,密码;最后,打开数据库连接。
通常,可以在 main( ) 函数中调用 createConnection( ) :
int main( int argc, char *argv[ ] ) { QApplication app(argc, argv); if (!createConnection()) return 1; ... return app.exec(); }
2. 执行 SELECT 命令
一旦建立连接,用户就可以使用 QSqlQuery 类型执行 SQL 命令。例如下面示例如何使用 SELECT 命令:QSqlQuery query; query.exec("SELECT title, year FROM cd WHERE year >= 2016") ;
或者直接写为:
QSqlQuery query("SELECT title, year FROM cd WHERE year >= 2016");
然后可以处理查询结果:
while (query.next()) { QString title = query.value(0).toString(); int year = query.value(1).toInt(); std::cerr << qPrintable(title) << ": " << year << std::endl; }
第一次调用 query.next( ) 时,查询记录指针指向第一条记录;接下来每调用一次 next( ),指针向后移一条记录,直到指针指向记录的尾端(尾端是最后一条记录的下一个位置),这时 next( ) 返回 false。
query.value( ) 函数返回记录中某个域的值,这个返回值的类型是 QVariant。像上面的例子中,查询记录中包括两个域:title 和 year,这些域从 0 开始编号。
除了上面的一些函数,像 first( ),last( ),previous( ),seek( ) 等函数也可用于对查询结果的记录指针进行偏移操作。但是对于访问大型的数据库时,通常的方法是在调用 exec( ) 之前,调用 QSqlQuery : : setForwardOnly(true) 进行指针偏移优化,然后在操作结果记录时只使用 next( ) 进行偏移。
在使用一个创建出来的 query 前,还可以调用 isActive( ) 查看是否有错误,如果没有错误就可以用上面的函数对结果进行查询操作:
if (!query.isActive()) QMessageBox::warning(this, tr("Database Error"),query.lastError().text());
3. 执行 INSERT 命令
QSqlQuery query("INSERT INTO cd (id, artistid, title, year) " "VALUES (20, 10, 'Living in America', 2016)");
也可以使用点位符替代记录中的值:
QSqlQuery query; query.prepare("INSERT INTO cd (id, artistid, title, year) " "VALUES (:id, :artistid, :title, :year)"); query.bindValue(":id", 20); query.bindValue(":artistid", 10); query.bindValue(":title", "Living in America"); query.bindValue(":year", 2016); query.exec();
上面的点位符是 Oracle 风格,不同的数据库管理系统有不同的点位符格式,下面的点位符具有 ODBC 风格:
QSqlQuery query; query.prepare("INSERT INTO cd (id, artistid, title, year) " "VALUES (?, ?, ?, ?)"); query.addBindValue(20); query.addBindValue(10); query.addBindValue("Living in America"); query.addBindValue(2016); query.exec();
执行 exec( ) 后,可以再调用 addBindValue 或者 bindValue 函数为点位符绑定新的值继续进行操作。
4. SQL transaction(互动,交易,事务)
Qt 可以在支持交易功能的数据库上进行这个操作。交易作用在 QSqlDatabase 对象上,完成交易需要调用 commit( ) 或者是 rollback( )。下面的示例展示在一个交易中,执行查询和插入的操作:QSqlDatabase::database().transaction(); QSqlQuery query; query.exec("SELECT id FROM artist WHERE name = 'Gluecifer'"); if (query.next()) { int artistId = query.value(0).toInt(); query.exec("INSERT INTO cd (id, artistid, title, year) " "VALUES (21, " + QString::number(artistId) + ", 'Riding the Tiger', 2016)"); } QSqlDatabase::database().commit();
QSqlDatabase::database( ) 函数返回一个 QSqlDatabase 对象,这个对象是在 createConnection( ) 函数中创建的。如果交易创建失败,transaction( ) 函数将返回 false。hasFeature( ) 函数可以用来检查某个数据库是否支持交易操作:
QSqlDriver *driver = QSqlDatabase::database().driver(); if (driver->hasFeature(QSqlDriver::Transactions))
5. 创建多个数据库连接
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL", "OTHER"); db.setHostName("swxctx.edu"); db.setDatabaseName("swxc"); db.setUserName("root"); db.setPassword("****");
通过传递给 database( ) driver 的名称,可以得到对应的 QSqlDatabase 对象的指针:
QSqlDatabase::database(); // 返回 QPSQL driver 的db QSqlDatabase db = QSqlDatabase::database("OTHER"); // 返回 OTHER driver 的db
通过返回的 db 可以初始化执行 SQL 操作的 QSqlQuery 对象:
QSqlQuery query(db); // OTHER driver 关联的 db query.exec("SELECT id FROM artist WHERE name = 'swxctx'");
6. QSqlTableModel
为了避免使用原始的 SQL 操作,Qt 提供了更高级的 QSqlTableModel 类,封装原始的 SQL 操作,提供更方便的接口。这个类可以直接操作一个数据库不需要涉及 GUI,或者它也可以作为 QListView 和 QTableView 的数据来源。下面是使用这个类进行 SELECT 操作的例子:QSqlTableModel model; model.setTable("cd"); model.setFilter("year >= 2016"); model.select();
这个代码相当于使用 SQL :
SELECT * FROM cd WHERE year >= 2016
遍历数据库中每一个记录的方法也很直接:
for (int i = 0; i < model.rowCount(); ++i) { QSqlRecord record = model.record(i); QString title = record.value("title").toString(); int year = record.value("year").toInt(); std::cerr << qPrintable(title) << ": " << year << std::endl; }
其中 QSqlTableModel : : record( ) 取得一个给定的记录,value( ) 通过域名,或者是域的索引取得域值。在大型的数据库中操作时,建议用域的索引指定某个域。例如:
int titleIndex = model.record().indexOf("title"); int yearIndex = model.record().indexOf("year"); for (int i = 0; i < model.rowCount(); ++i) { QSqlRecord record = model.record(i); QString title = record.value(titleIndex).toString(); int year = record.value(yearIndex).toInt(); std::cerr << qPrintable(title) << ": " << year << std::endl; }
插入的操作也很直接,insertRow( ) 插入一行空的记录,setData( ) 则设置此行记录中每一个域值:
QSqlTableModel model; model.setTable("cd"); int row = 0; model.insertRows(row, 1); model.setData(model.index(row, 0), 110); model.setData(model.index(row, 1), "swxctx"); model.setData(model.index(row, 2), 220); model.setData(model.index(row, 3), 2016); model.submitAll();
插入的行实际位于数据库中哪一行,取决于当前数据库记录的排序次序。如果插入失败,submitAll( ) 函数返回 false。
为了更新一条记录,首先从 QSqlTableModel 中找到该记录的位置。然后抽出记录,更新域值,再将记录写入数据库:
QSqlTableModel model; model.setTable("cd"); model.setFilter("id = 12"); model.select(); if (model.rowCount() == 1) { QSqlRecord record = model.record(0); record.setValue("title", "Melody A.M."); record.setValue("year", record.value("year").toInt() + 1); model.setRecord(0, record); model.submitAll(); }
更新记录的另一种办法是使用 setData( ):
model.select(); if (model.rowCount() == 1) { model.setData(model.index(0, 1), "Melody A.M."); model.setData(model.index(0, 3), model.data(model.index(0, 3)).toInt() + 1); model.submitAll(); }
删除一条记录的只得类似更新操作:
model.setTable("cd"); model.setFilter("id = 12"); model.select(); if (model.rowCount() == 1) { model.removeRows(0, 1); model.submitAll(); }
这个例子中,removeRows( ) 第一个参数是得到的 model 中的第一行(以 0 索引),第二个参数是需要删除的记录条数(这里是一条)。删除所有满足条件的记录则如下:
model.setTable("cd"); model.setFilter("year < 2015"); model.select(); if (model.rowCount() > 0) { model.removeRows(0, model.rowCount()); model.submitAll(); }
相关文章推荐
- LR11如何打开回放结果窗口 “Results.qtp”,
- Qt 的sqlite数据库的学习
- NANOPI2 编译QT+sqlite 问题解决方式
- 详解 Qt 4访问Sqlite数据库
- Qt布局管理: 堆栈窗体QStackedWidget类(纯代码实现)
- 为什么Qt编程出现No signal?
- qt在Windows下调用动态库
- qt在Windows下生成包含动态库的动态库
- Qt-MapX
- Qt获取系统默认图标,显示到QListWidget内
- Qt5.1.0 MinGW480 release静态版编译结果及过程分享
- Qt 4.8.4中文显示问题
- 【opencv学习之二】opencv与qt图像格式交换IplImage-->QImage
- Qt简易计算器的代码实现
- Qt的皮肤设计(Style Sheet)
- 从 Qt 的 delete 说开来
- ubuntu下配置qt+opengl+opencv
- VS2013 Qt5 Mysql中文编码问题
- Qt 多线程与数据库操作需要注意的几点问题
- qt执行cmd命令