Qt SQLite數據庫操作

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)
 
運行結果:
20131114230655.png
 
--------------------------------
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
發佈了5 篇原創文章 · 獲贊 37 · 訪問量 33萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章