Qt操作SQLite数据库
Qt提供了一种进程内数据库SQLite。它小巧灵活,无须额外安装配置且支持大部分ANSI SQL92标准,是一个轻量级的数据库,概括起来具有以下优点。
- (1)SQLite的设计目的是实现嵌入式SQL数据库引擎,它基于纯C语言代码,已经应用在非常广泛的领域内。
- (2)SQLite在需要持久存储时可以直接读写硬盘上的数据文件,在无须持久存储时也可以将整个数据库置于内存中,两者均不需要额外的服务器端进程,即SQLite是无须独立运行的数据库引擎。
- (3)开放源代码,整套代码少于3万行,有良好的注释和90%以上的测试覆盖率。
- (4)少于250KB的内存占用容量(gcc编译情况下)。
- (5)支持视图、触发器和事务,支持嵌套SQL功能。
- (6)提供虚拟机用于处理SQL语句。
- (7)不需要配置,不需要安装,也不需要管理员。
- (8)支持大部分ANSI SQL92标准。
- (9)大部分应用的速度比目前常见的客户端/服务器结构的数据库快。
- (10)编程接口简单易用。
操作数据库实例
基于控制台的程序,使用SQLite数据库完成大批量数据的增加、删除、更新和查询操作并输出。
操作步骤如下。
(1)在“QSQLiteEx.pro”文件中添加如下代码:
QT += sql
(2)源文件“main.cpp”的具体代码。
#include <QCoreApplication>
#include<QSqlDatabase>
#include<QSqlError>
#include<QSqlQuery>
#include<QSqlDriver>
#include<QSqlRecord>
#include<QTextCodec>
#include<QDebug>
#include<QTime>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTextCodec::setCodecForLocale (QTextCodec::codecForLocale ());//设置中文显示
//以QSQLITE为数据库类型,在本进程地址空间内创建一个SQLite数据库,
QSqlDatabase db = QSqlDatabase::addDatabase ("QSQLITE");
db.setHostName ("easybook-3313b0");//设置数据库主机名
db.setDatabaseName ("qtDB.db");//设置数据库主机名
db.setUserName ("Luo");//设置数据库用户名
db.setPassword ("123456");//设置数据库密码
db.open ();//打开连接
//创建数据库表
QSqlQuery query;
bool success = query.exec ("create table automobile"
"(id int primary key,"//设置id为主关键字
"attribute varchar,"
"type varchar,"
"kind varchar,"
"nation int,"
"carnumber int,"
"elevaltor int,"
"distance int,"
"oil int,"
"temperature int)"
);
if(success)
qDebug() << "数据库表创建成功!";
else
qDebug() << "创建失败";
//查询
query.exec ("select * from automobile");
QSqlRecord rec = query.record ();
qDebug() << "automobile表字段数:"<<rec.count ();
//插入记录
QTime t;
t.start();//启动一个计时器,统计操作时间
query.prepare ("insert into automobile values(?,?,?,?,?,?,?,?,?,?)");
long records = 100;
//向表中任意插入100条记录
for(int i=0; i<records; i++)
{
query.bindValue (0,i);
query.bindValue (1,"四轮");
query.bindValue (2,"轿车");
query.bindValue (3,"富康");
query.bindValue (4,rand ()%100);
query.bindValue (5,rand ()%10000);
query.bindValue (6,rand ()%300);
query.bindValue (7,rand ()%200000);
query.bindValue (8,rand ()%52);
query.bindValue (9,rand ()%100);
success = query.exec ();
if(!success)
{
QSqlError lastError = query.lastError ();
qDebug() << lastError.driverText ()<<"插入失败";
}
}
qDebug() << QString("插入 %1 条记录,耗时:%2ms").arg (records).arg (t.elapsed ());
//排序
t.restart ();//重启计时器
success = query.exec ("select * from automobile order by id desc");
if(success)
qDebug() << QString("排序 %1 条记录,耗时:%2 ms").arg (records).arg (t.elapsed ());
else
qDebug() << "排序失败";
//更新记录
t.restart ();
for(int i=0; i<records; i++)
{
query.clear ();
query.prepare (QString("update automobile set attribute=?,"
"type=?,"
"kind=?,"
"nation=?"
"carnumber=?,elevaltor=?,"
"distance=?,oil=?,"
"temperature=? where id=%1").arg (i));
query.bindValue (0,"四轮");
query.bindValue (1,"轿车");
query.bindValue (2,"富康");
query.bindValue (3,rand ()%100);
query.bindValue (4,rand ()%10000);
query.bindValue (5,rand ()%300);
query.bindValue (6,rand ()%200000);
query.bindValue (7,rand ()%52);
query.bindValue (8,rand ()%100);
success = query.exec ();
if(!success)
{
QSqlError lastError = query.lastError ();
qDebug() << lastError.driverText ()<<QString("更新失败");
}
}
qDebug() << QString("更新 %1 条记录,耗时:%2 ms").arg (records).arg (t.elapsed ());
//删除
t.restart ();
query.exec ("delete from automobile where id=15");
qDebug() << QString("删除一条记录,耗时:%1 ms").arg (t.elapsed ());
return 0;
//return a.exec();
}
注意:上述代码执行一遍后会在具体的编译文件夹中生成qtDB.db文件,里面有一个automobile的表格,如果再执行一遍上述代码,会提示数据库表创建失败,更改表格的名字重新创建一个即可。
其中,
(a) QSqlDatabase db =QSqlDatabase::addDatabase("QSQLITE"):以“QSQLITE”为数据库类型,在本进程地址空间内创建一个SQLite数据库。此处涉及的知识点有以下两点。
① 在进行数据库操作之前,必须首先建立与数据库的连接。数据库连接由任意字符串标识。在没有指定连接的情况下,QSqlDatabase可以提供默认连接供Qt其他的SQL类使用。
其中,静态函数QSqlDatabase::addDatabase()返回一条新建立的数据库连接,其原型为:
QSqlDatabase::addDatabase
(
const QString &type,
const QString &connectionName=QLatin1String(defaultConnection)
)
参数type为驱动名,本例使用的是QSQLITE 驱动。 参数connectionName为连接名,默认值为默认连接,本例的连接名为connect。如果没有指定此参数,则新建立的数据库连接将成为本程序的默认连接,并且可以被后续不带参数的函数database()引用。如果指定了此参数(连接名),则函数database(connectionName)将获取这个指定的数据库连接。
② QtSql模块使用驱动插件(driver plugins)与不同的数据库接口通信。由于QtSql模块的应用程序接口是与具体数据库无关的,所以所有与数据库相关的代码均包含在这些驱动插件中。目前,Qt支持的数据库驱动插件见表
驱 动 | 数据库管理系统 |
QDB2 | IBM DB2及其以上版本 |
QIBASE | Borland InterBase |
QMYSQL | MySQL |
QOCI | Oracle Call Interface Driver |
QODBC | Open Database Connectivity(ODBC)包括Microsoft SQL Server和其他ODBC兼容数据库 |
QPSQL | PostgreSQL版本6.x和7.x |
QSQLITE | SQLite版本3及其以上版本 |
QSQLITE2 | SQLite版本2 |
QTDS | Sybase Adaptive Server |
(b) db.setDatabaseName("qtDB.db"):以上创建的数据库以“qtDB.db”为数据库名。它是SQLite在建立内存数据库时唯一可用的名字。
(c) QSqlQuery query:创建QSqlQuery对象。QtSql模块中的QSqlQuery类提供了一个执行SQL语句的接口,并且可以遍历执行的返回结果集。除QSqlQuery类外,Qt还提供了三种用于访问数据库的高层类,即QSqlQueryModel、QSqlTableModel和QSqlRelationTableModel。它们无须使用SQL语句就可以进行数据库操作,而且可以很容易地将结果在表格中表示出来。访问数据库的高层类见表
类 名 | 用 途 |
QSqlQueryModel | 基于任意SQL语句的只读模型 |
QsqlTableModel | 基于单个表的读写模型 |
QSqlRelationalTableModel | QSqlTableModel的子类,增加了外键支持 |
(d) bool success=query.exec("create table automobile…"):创建数据库表“automobile”,该表具有10个字段。在执行exec()函数调用后,就可以操作返回的结果了。
(e) query.prepare("insert into automobil values(?,?,?,?,?,?,?,?,?,?)"):如果要插入多条记录,或者避免将值转换为字符串(即正确地转义),则可以首先调用prepare()函数指定一个包含占位符的query,然后绑定要插入的值。Qt对所有数据库均可以支持Qracle类型的占位符和ODBC类型的占位符。此处使用了ODBC类型的定位占位符。
等价于使用Oracle语法的有名占位符的具体形式如下:
query.prepare("insert into automobile(id,attribute,type,kind,nation,
carnumber,elevaltor,distance,oil,temperature)
values(:id, :attribute, :type, :kind, :nation,
:carnumber,:elevaltor,:distance,:oil,:temperature)");
long records=100;
for(int i=0;i<records;i++)
{
query.bindValue(:id,i);
query.bindValue(:attribute,"四轮");
query.bindValue(:type,"轿车");
query.bindValue(:kind,"富康");
query.bindValue(:nation,rand()%100);
query.bindValue(:carnumber,rand()%10000);
query.bindValue(:elevaltor,rand()%300);
query.bindValue(:distance,rand()%200000);
query.bindValue(:oil,rand()%52);
query.bindValue(:temperature,rand()%100);
}
(f) query.bindValue(0,i):调用bindValue()或addBindValue()函数绑定要插入的值。
(g) success=query.exec():调用exec()函数在query中插入对应的值,之后,可以继续调用bindValue()或addBindValue()函数绑定新值,然后再次调用exec()函数在query中插入新值。
(h) qDebug()<<QObject::tr("插入 %1 条记录,耗时:%2 ms").arg(records).arg (t.elapsed()):向表中插入任意的100条记录,操作成功后输出操作消耗的时间。
(i) success=query.exec("select * from automobile order by id desc"):按id字段的降序将查询表中刚刚插入的100条记录进行排序。
(j) query.prepare(QString("update automobile set…")):更新操作与插入操作类似,只是使用的SQL语句不同。
(k) query.exec("delete from automobile where id=15"):执行删除id为15的记录的操作。
执行结果:
automobile表字段数: 10
"插入 100 条记录,耗时:16607ms"
"排序 100 条记录,耗时:1 ms"
"更新 100 条记录,耗时:18269 ms"
"删除一条记录,耗时:0 ms"
实例2:
#include <QCoreApplication>
#include<QSqlDatabase>
#include<QSqlError>
#include<QSqlQuery>
#include<QSqlDriver>
#include<QSqlRecord>
#include<QTextCodec>
#include<QDebug>
#include<QTime>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTextCodec::setCodecForLocale (QTextCodec::codecForLocale ());//设置中文显示
//以QSQLITE为数据库类型,在本进程地址空间内创建一个SQLite数据库,
QSqlDatabase db = QSqlDatabase::addDatabase ("QSQLITE");
db.setHostName ("easybook-3313b0");//设置数据库主机名
db.setDatabaseName ("qtDB.db");//设置数据库主机名
db.setUserName ("Luo");//设置数据库用户名
db.setPassword ("123456");//设置数据库密码
db.open ();//打开连接
//创建数据库表
QSqlQuery query;
bool success;
//查询
success = query.exec ("select * from automobile");
if(success)
qDebug() << "查询成功!";
else
qDebug() << "查询失败";
// record()返回的是当前query的字段信息,也就是表头,
//如果query指向一个有效行,将返回那一行的数据
QSqlRecord rec = query.record ();
//打印表头
qDebug() << "打印表头:";
int index=0;
QStringList fieldList;
while(!rec.fieldName (index).isEmpty ())
{
fieldList << rec.fieldName (index++);
}
qDebug() << fieldList;
qDebug() << "automobile表字段数(列数):"<<rec.count ();
//返回指定字段的下标
int idIndex = rec.indexOf ("id");
qDebug() << "idIndex:"<<idIndex;
/* bool QSqlQuery::next()
* 将query指向查询结果的下一个
* 规则:
* 1,如果当前query就是最后一条记录,将不改变query,直接返回false
* 2,正常情况:将查询结果指向下一个,返回true
*/
query.next();
query.next();//将指向第2行数据
QVariant value = query.value (idIndex);
qDebug() << "第二行id:" <<value.toString ();
//打印其余id
while (query.next())
qDebug() << query.value(idIndex).toString(); // output all names
//使用的是 INSERT INTO tableName VALUES(...) 格式,注意字符串要打单引号‘’
success = query.exec ("insert into automobile values("
"666,'三轮','bycycle','Benz',8,8848999,123,987654321,"
"100,6"
")");
if(success)
qDebug() << "插入成功!";
else
qDebug() << "插入失败";
return 0;
}
查询成功!
打印表头:
("id", "attribute", "type", "kind", "nation", "carnumber", "elevaltor", "distance", "oil", "temperature")
automobile表字段数(列数): 10
idIndex: 0
第二行id: "1"