Qt SQLite数据库操作

时间:2022-04-24 10:59:48
Qt提供了平台以及数据库种类无关的访问数据库接口,支持 QMYSQL,QODBC ,QPSQL和QSQLITE. 由于Qt对不同平台和数据库都使用同一个接口,本文选择了对嵌入式领域常用的SQLite数据库进行操作。
-----------------
SQLite 数据库
-----------------
        SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源世界著名的数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月。 至今已经有13个年头,SQLite也迎来了一个版本 SQLite 3已经发布。

        不像常见的客户-服务器范例,SQLite引擎不是个程序与之通信的独立进程,而是连接到程序中成为它的一个主要部分。所以主要的通信协议是在编程语言内的直接API调用。这在消耗总量、延迟时间和整体简单性上有积极的作用。整个数据库(定义、表、索引和数据本身)都在宿主主机上存储在一个单一的文件中(eg. test.db)。它的简单的设计是通过在开始一个事务的时候锁定整个数据文件而完成的。
 
----------------
SQLite 数据库移植
-----------------
 
1.下载并解压数据库
  从sqlite 官网下载最新的源码包 http://www.sqlite.org/download.html  现在最新版本为3080100版本
  下载完成后解压: tar -zxvf sqlite-autoconf-3080100.tar.gz
 
2.交叉编译
  a.解压完成之后,进入解压后的目录:
    cd sqlite-autoconf-3080100 
  b.在这个目录之中新建一个文件夹,用于放置最后交叉编译生成的程序包: 
    mkdir build
  c.文件夹中运行 sqlite-autoconf-3080100中的configure脚本生成Makefile文件: 
    ./configure   --prefix=/文件夹的绝对路径/ssqlite-autoconf-3080100/build
--Prefix:可以指定编译之后目标存放的路径,可自行设定
       还可以通过 --host=arm-linux  指定使用 arm交叉编译器进行交叉编译 以供嵌入式系统使用
  d.然后运行指令: 
    make 
    make install 
3.编译和安装完成之后,在我们指定的路径/文件夹的绝对路径/ssqlite-autoconf-3080100/build 下会生成四个文件夹:
  bin、lib、include、share,将bin中的文件拷贝至开发板的/usr/bin中,将lib文件夹中的所有内容拷贝至项目lib文件夹中
 
4.测试数据库 
  先将/usr/bin/sqlite3的权限修改一下:
  chmod 755 sqlite3 
  然后在开发板的终端中输入指令:
  sqlite3 test.db
  执行的结果为: 
SQLite version 3.8.1 2013-10-17 12:57:35
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>
  此时表明Sqlite3已经移植成功
 
----------------------------
Qt 操作SQlite数据库
----------------------------
 
 1.创建测试数据库
       create table qttest([id] integer PRIMARY KEY autoincrement, [userName] varchar(32), [userPwd] varchar(32));
   添加测试数据记录
       insert into qttest(id,userName,userPwd) values(NULL,"apple","123456");
       insert into qttest(id,userName,userPwd) values(NULL,"orange","123456");
  
 2.创建qt项目,将 test.db 放在qt的项目文件夹,并在qt工程文件(xxx.pro)里 添加:
            QT += sql
 
3. qt操作数据库代码:
 
01 #include <QApplication>
02 #include <QMessageBox>
03 #include <QtSql>
04 #include <QDebug>
05  
06 bool dbConnect(char *dbname)
07 {
08     QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
09     //QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
10     //db.setHostName(host);
11     db.setDatabaseName(dbname);
12     //db.setUserName(user);
13     //db.setPassword(pwd);
14  
15     if(!db.open())
16     {
17         qDebug()<<"Database Error!"<<db.lastError().text();
18         return false;
19     }else{
20         qDebug()<<"Database Success!";
21         return true;
22     }
23 }
24  
25  
26 int main(int argc,char *argv[])
27 {
28     QApplication app(argc,argv);
29  
30     int iRet=0;
31  
32     iRet=dbConnect((char *)"test.db");
33     if(iRet == false)
34         return -1;
35  
36     QSqlQuery query;
37     query.exec("select id,userName,userPwd from qttest");
38  
39     //检查query是否生效
40     if(!query.isActive())
41     {
42         qDebug()<<"Query Error!"<<query.lastError().text();
43         return -2;
44     }
45  
46 /*
47     //qt可能对sqlLite支持不够好,此接口会导致错误
48     //检查上一条SQL语句 有多少记录受影响
49     iRet=query.numRowsAffected();
50     if(!iRet)
51     {
52         qDebug()<<"NO Record!";
53         return -3;
54     }else{
55         qDebug()<<"Find "<<iRet<<" Records!";
56     }
57 */
58     //轮循各记录
59     while(query.next()){
60         int id = query.value(0).toInt();
61         QString name = query.value(1).toString();
62         QString pwd = query.value(2).toString();
63         qDebug()<<"user info: id= "<<id<<",name= "<<name<<",pwd= "<<pwd;
64     }
65  
66     //插入数据
67     query.exec("insert into qttest(id,userName,userPwd) values(null,\"ox\",\"123456\")");
68     //更新数据
69     query.exec("update qttest set userPwd= \"1111\" where id=\"1\"");
70  
71 /*
72     //qt可能对sqlLite支持不够好,此接口会导致错误
73     //ODBC风格插入数据
74     query.prepare("insert into qttest(id,userName,userPwd) values(?,?,?)");
75     query.addBindValue("null");
76     query.addBindValue("dog");
77     query.addBindValue("hello");
78     query.exec();
79 */
80     app.exec();
81 }
 
经验证,Qt对SQlite数据库的支持可能存在问题. 同样的数据内容,操作MYSQL就不存在问题,但是操作SQlite,就不支持 numRowsAffected()接口 和 ODBC风格的插入操作.
原因不祥,如果是代码或是数据库配置等其他原因,望能得到指点。(平台环境:Ubuntu + Qt Creator 4.8)
 
运行结果:
Qt SQLite数据库操作
 
--------------------------------
SQLite 数据库 C/C++ 接口
--------------------------------
 
SQLite 提供了 C/C++ 接口的API函数,这些接口使用起来并不复杂. 最简单的程序仍然使用三个函数就可以完成: sqlite3_open(), sqlite3_exec(), 和 sqlite3_close(). 
 
 
1. 核心对象:
    在SQLite中最主要的两个对象是,database_connection和prepared_statement。 database_connection对象是由sqlite3_open()接口函数创建并返回的,在应用程序使用任何其他SQLite接口函数之前,必须先调用该函数以便获得database_connnection对象,在随后的其他APIs调用中,都需要该对象作为输入参数以完成相应的工作。至于 prepare_statement,我们可以简单的将它视为编译后的SQL语句,因此,所有和SQL语句执行相关的函数也都需要该对象作为输入参数以完成指定的SQL操作。
 
2. 核心接口:
    1). sqlite3_open
    上面已经提到过这个函数了,它是操作SQLite数据库的入口函数。该函数返回的database_connection对象是很多其他SQLite APIs的句柄参数。注意,我们通过该函数既可以打开已经存在的数据库文件,也可以创建新的数据库文件。对于该函数返回的 database_connection对象,我们可以在多个线程之间共享该对象的指针,以便完成和数据库相关的任意操作。然而在多线程情况下,我们更为推荐的使用方式是,为每个线程创建独立的database_connection对象。对于该函数还有一点也需要额外说明,我们没有必要为了访问多个数据库而创建多个数据库连接对象,因为通过SQLite自带的ATTACH命令可以在一个连接中方便的访问多个数据库。
        
    2). sqlite3_prepare
    该函数将SQL文本转换为prepared_statement对象,并在函数执行后返回该对象的指针。事实上,该函数并不会评估参数指定SQL语句,它仅仅是将SQL文本初始化为待执行的状态。最后需要指出的,对于新的应用程序我们可以使用sqlite3_prepare_v2接口函数来替代该函数以完成相同的工作。
    
    3). sqlite3_step
    该函数用于评估sqlite3_prepare函数返回的prepared_statement对象,在执行完该函数之后,prepared_statement对象的内部指针将指向其返回的结果集的第一行。如果打算进一步迭代其后的数据行,就需要不断的调用该函数,直到所有的数据行都遍历完毕。然而对于INSERT、UPDATE和DELETE等DML语句,该函数执行一次即可完成。
    
    4). sqlite3_column
    该函数用于获取当前行指定列的数据,然而严格意义上讲,此函数在SQLite的接口函数中并不存在,而是由一组相关的接口函数来完成该功能,其中每个函数都返回不同类型的数据,如:
    sqlite3_column_blob
    sqlite3_column_bytes
    sqlite3_column_bytes16
    sqlite3_column_double
    sqlite3_column_int
    sqlite3_column_int64
    sqlite3_column_text
    sqlite3_column_text16
    sqlite3_column_type
    sqlite3_column_value
    sqlite3_column_count
    其中sqlite3_column_count函数用于获取当前结果集中的字段数据。
 
   5). sqlite3_finalize
    该函数用于销毁prepared statement对象,否则将会造成内存泄露。
    
    6). sqlite3_close
    该函数用于关闭之前打开的database_connection对象,其中所有和该对象相关的prepared_statements对象都必须在此之前先被销毁。
 
使用 SQLite API操作数据库:
01 #include <stdio.h>
02 #include <sqlite3.h>
03  
04  
05 int main()
06 {
07     int iRet=0;
08     char *ErrMsg;
09     sqlite3 *db=NULL;
10     sqlite3_stmt *ppStmt=NULL;
11  
12     iRet = sqlite3_open("test.db", &db);
13     if(iRet)
14     {
15       printf("Can't open database: %s\n", sqlite3_errmsg(db));
16       sqlite3_close(db);
17       return -1;
18     }else{
19       printf("open database!\n");
20     }
21  
22     /******************************************************************************
23     int sqlite3_exec(
24       sqlite3*,                                  // An open database
25       const char *sql,                           // SQL to be evaluated
26       int (*callback)(void*,int,char**,char**),  // Callback function
27       void *,                                    // 1st argument to callback
28       char **errmsg                              // Error msg written here
29     );
30     ********************************************************************************/
31     //不使用回调函数
32     iRet = sqlite3_exec(db, "insert into qttest(id,userName,userPwd) values(null,\"cat\",\"123456\")", NULL, NULL, &ErrMsg);
33     if( iRet !=SQLITE_OK )
34     {
35       printf("SQL error: %s\n", ErrMsg);
36       return -2;
37     }else{
38       printf("insert ok! \n");
39     }
40  
41     /******************************************************************************
42     int sqlite3_prepare(
43       sqlite3 *db,            // Database handle
44       const char *zSql,       // SQL statement, UTF-8 encoded
45       int nByte,              // Maximum length of zSql in bytes
46       sqlite3_stmt **ppStmt,  // OUT: Statement handle
47       const char **pzTail     // OUT: Pointer to unused portion of zSql
48     );
49     ********************************************************************************/
50     //数据库取数据,最大长度无效
51     iRet = sqlite3_prepare(db,"select id,userName,userPwd from qttest", -1, &ppStmt, NULL);
52     if( iRet != SQLITE_OK )
53     {
54         printf("Select error\n");
55         //释放ppStmt
56         sqlite3_finalize(ppStmt);
57         return -3;
58     }else{
59         printf("user info:\n");
60         while(sqlite3_step(ppStmt) == SQLITE_ROW)
61         {
62             printf("Id: %s\t", sqlite3_column_text(ppStmt, 0));
63             printf("Name: %s\t", sqlite3_column_text(ppStmt, 1));
64             printf("Pwd: %s\n", sqlite3_column_text(ppStmt, 2));
65         }
66         sqlite3_finalize(ppStmt);
67     }
68  
69     sqlite3_close(db);
70     return 0;
71 }

转载:http://www.ichanging.org/qt-sqlite.html