Qt中的QtSql模块提供了对数据库的支持,该模块可以分为三大类别:用户接口层、SQL接口层、驱动层. 其中驱动层是具体数据和SQL接口层之间提供了底层的桥梁;SQL接口层提供了对数据库的访问,其中QSqlDatabase类用来创建链接,QSqlQuery类可以使用SQL语句实现与数据库的交互.
讲在多的理论还不如真刀真抢的来实战,下面我配合代码来讲解QT对数据库的基本操作.
新建空的Qt项目,项目名称databaseDriver,完成后
往项目添加新的main.cpp.connect.h 还需要在databaseDriver.pro文件中添加QT+=sql ,connect.h文件内容如下:
#ifndef CONNECTION_H #define CONNECTION_H #include <QMessageBox> #include <QSqlDatabase> #include <QSqlQuery> static bool createConnection() { QSqlDatabase db1 = QSqlDatabase::addDatabase("QSQLITE"); //db1.setDatabaseName(":memory:"); /* 表明是建立在内存中的数据库 */ db1.setDatabaseName("my1.db"); if (!db1.open()) { QMessageBox::critical(0, "Cannot open database", "Unable to establish a database connection.", QMessageBox::Cancel); return false; } QSqlQuery query1(db1); query1.exec("create table student (id int primary key, " "name varchar(20))"); query1.exec("insert into student values(0, 'LiMing')"); query1.exec("insert into student values(1, 'LiuTao')"); query1.exec("insert into student values(2, 'WangHong')"); QSqlDatabase db2 = QSqlDatabase::addDatabase("QSQLITE"); db2.setDatabaseName("my2.db"); if (!db2.open()) { QMessageBox::critical(0, "Cannot open database", "Unable to establish a database connection.", QMessageBox::Cancel); return false; } QSqlQuery query2(db2); query2.exec("create table student (id int primary key, " "name varchar(20))"); query2.exec("insert into student values(0, 'LiMing')"); query2.exec("insert into student values(1, 'LiuTao')"); query2.exec("insert into student values(2, 'WangHong')"); return true; } #endif // CONNECTION_H
部分讲解在注释中已经表明,本文由Linux_Google创建.
这个头文件添加了一个与数据库建立链接的函数,第一行创建了一个SQLite数据库的默认连接,设置数据库名称使用了:memory:表明这个是建立在内存中的数据,my1.db表明是建立在文件中的,db1.open()打开这个数据文件.QSqlQuery创建一个操作数据库的对象,可以传入参数是数据库文件,query1.exec是运行数据库命令的封装函数.
main.cpp文件内容如下
#include <QApplication> #include <QSqlDatabase> #include <QDebug> #include <QStringList> #include "connection.h" #include <QVariant> #include <QSqlDriver> #include <QSqlRecord> #include <QSqlField> #include <QSqlError> int main(int argc, char *argv[]) { int numRows; QApplication a(argc, argv); qDebug() << "Available drivers:"; QStringList drivers = QSqlDatabase::drivers(); /* 查询所拥有的SQL驱动程序 */ foreach(QString driver, drivers) qDebug() << driver; if (!createConnection()) return 1; QSqlDatabase db1 =QSqlDatabase::database("connection1"); QSqlQuery query1(db1); query1.exec("select * from student"); /* next()下一条记录 previous()上一条记录,first()定位到第一条记录,last()定位到最后一条记录 seek(n)定位到第n条记录*/ while(query1.next()) { qDebug() << query1.value(0).toInt() << query1.value(1).toString(); } QSqlDatabase db2 =QSqlDatabase::database("connection1"); QSqlQuery query2(db2); query2.exec("select * from student"); while(query2.next()) { qDebug() << query2.value(0).toInt() << query2.value(1).toString(); } /* 判断该数据库驱动是否支持QuerySize特性,如果支持,则可以使用size()函数 */ if(db2.driver()->hasFeature(QSqlDriver::QuerySize)) { qDebug() << "has feauter:query size"; numRows =query2.size(); } else { qDebug() << "no feauter:query size"; query2.last(); numRows =query2.at()+1; } qDebug() << "num number:" << numRows; query2.seek(1); /* index is 1,also two line */ qDebug() << "current index:" << query2.at(); QSqlRecord record = query2.record(); int id =record.value("id").toInt(); QString name = record.value("name").toString(); qDebug() << "id:" << id << "name:" << name; /* 获取索引为1的字段,即第二个字段,name */ QSqlField field = record.field(1); /* 输出字段名和字段值 */ qDebug() << "second field:" << field.name() << "field value:" << field.value(); /* 下面两种情况是等价的 */ #if 1 query2.exec("insert into student (id, name) values (520, 'Linux_Google')"); #else /* 名称绑定 */ query2.prepare("inset into student (id,name) values(:id,:name)"); int idValue = 520; QString nameValue = "Linux_Google"; query2.bindValue(":id",idValue); query2.bindValue(":name",nameValue); query2.exec(); //query2.prepare("insert into student (id, name) values (?, ?)"); /* 或者可以用下面几条语句替换,这个是位置绑定 */ // int idValue = 520; // QString nameValue = "Linux_Google"; // query2.addBindValue(idValue); // query2.addBindValue(nameValue); // query2.exec(); #endif query2.prepare("insert into student (id, name) values (?, ?)"); QVariantList ids; ids << 20 << 21 << 22; query2.addBindValue(ids); QVariantList names; names << "xiaoming" << "xiaoliang" << "xiaogang"; query2.addBindValue(names); if(!query2.execBatch()) qDebug() << query2.lastError(); query2.exec("update student set name = 'xiaohong' where id = 20"); query2.exec("delete from student where id = 21"); query2.exec("delete from student where name = ChenYun"); query2.exec("select * from student"); while(query2.next()) { qDebug() << query2.value(0).toInt() << query2.value(1).toString(); } return a.exec(); }QSqlDatabase::drivers()获取本机上可用的数据库驱动列表,foreach遍历输出.用createConnection建立了一个连接,然后创建了两个数据库操作对象query1,query2分别指向db1,db2.query1.next()作用是输出遍历到的库文件,输出一行后自动将索引值加1.query2.size()是来判断数据库文件的行数的,前提是看看是否支持这个函数,程序中有判断.
程序中有四种方法插入数据库文件,
直接插入
query2.exec("insert into student (id, name) values (520, 'Linux_Google')");
名称绑定插入法
query2.prepare("inset into student (id,name) values(:id,:name)"); int idValue = 520; QString nameValue = "Linux_Google"; query2.bindValue(":id",idValue); query2.bindValue(":name",nameValue); query2.exec(); 位置绑定插入法:
//query2.prepare("insert into student (id, name) values (?, ?)"); // int idValue = 520; // QString nameValue = "Linux_Google"; // query2.addBindValue(idValue); // query2.addBindValue(nameValue); // query2.exec(); 多项同时插入法:
query2.prepare("insert into student (id, name) values (?, ?)"); QVariantList ids; ids << 20 << 21 << 22; query2.addBindValue(ids); QVariantList names; names << "xiaoming" << "xiaoliang" << "xiaogang"; query2.addBindValue(names); if(!query2.execBatch()) qDebug() << query2.lastError(); query2.execBatch()是用来判断插入出错操作,剩下的就是操作数据库文件的一些指令,比较简单.
代码中用到了一个库函数QVariant,QVariant是一种可以存储不同类型的数据结构,比QStringList更加强大.
最后一个知识点在代码中没有体现,那就是事务.用我们Linux内核的解释就是竞争冒险,原子变量操作.事务操作可以保证一个事务操作的原子性,就是对一个数据的操作序列,它会把数据库操作看成一个不可分割的工作单位.如果底层数据库支持事务的话,那么QSqlDatabase::database().transaction();来启动一个事务,QSqlDatabase::database().commit();或QSqlDatabase::database().rollback(); 结束这个事务,当使用事务时必须在创建查询以前就开始事务,也就是说我们操作数据库用事务就需要在启动和停止之间.
文章出自:Linux_Google
