qt+sqlite3

   目前想学习下sqlite数据库编程。之前在开发板上运行Qt程序时,出现了只能读数据库,不能进行写入的情况。在网上查得可以不使用Qt自带的数据库,重新编译一个sqlite3库,然后在Qt中使用这个库就可以了。为了使学习的更为全面,报着认真敲代码的态度,我将这个学习过程以博客的形式写出来。对程序中可能出现的问题,尽量不留死角。同时,在后面尽量解决以前遇到的问题。

    现在开发工具如下:

    smart210开发板,linux3.0.8内核,qt4.8.6程序库,虚拟机ubuntu12.04系统,交叉编译器arm-linux-gcc 4.5.1。

    首先是配置下环境,qte库在友善之臂中的光盘中已经给出,这里我简单说一下sqlite3的编译。首先进入源码目录,执行 “./configure --help > help.txt” 命令,将帮助信息打印到help.txt文件中,打开这个文件,可看到如下说明:

[plain]  view plain  copy
  1. Installation directories:  
  2.   --prefix=PREFIX         install architecture-independent files in PREFIX  
  3.                           [/usr/local]  
  4. System types:  
  5.   --build=BUILD     configure for building on BUILD [guessed]  
  6.   --host=HOST       cross-compile to build programs to run on HOST [BUILD]  
  7. Some influential environment variables:  
  8.   CC          C compiler command  
  9.   CFLAGS      C compiler flags  
  10.   LDFLAGS     linker flags, e.g. -L if you have libraries in a  
  11.               nonstandard directory   
  12.   LIBS        libraries to pass to the linker, e.g. -l  
  13.   CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I if  
  14.               you have headers in a nonstandard directory   
  15.   CPP         C preprocessor  

    这里设置prefix(安装目录)、host(目标平台)、CC(编译器)这三个参数即可。命令 “./configure --prefix=/usr/local/arm_sqlite --host=arm-linux CC=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-linux-gcc” 。然后 make,make install。

    下面开始第一个qt+sqlite3工程。

    首先建立一个Qt Widgets Application 工程,这里命名为1_sqlite3。在工程文件1_sqlite3.pro中添加下面两行代码,来指定sqlite3的库与头文件位置。

[cpp]  view plain  copy
  1. LIBS += -L/usr/local/arm_sqlite/lib -lsqlite3  
  2. INCLUDEPATH += /usr/local/arm_sqlite/include  
    接下来创建ui界面如下。

qt+sqlite3_第1张图片

    这里工程要实现sqlite3的基本功能,如:创建一个表格、删除一个表格、插入一行数据、删除一行数据、查询一条数据并显示。

    首先看数据库的打开,代码如下。

[cpp]  view plain  copy
  1. //连接数据库  
  2.     int ret = sqlite3_open("./test.db", &db);  
  3.     if (ret != SQLITE_OK)  
  4.     {  
  5.         fprintf(stderr, "Cannot open datebase %s\n", sqlite3_errmsg(db));  
  6.         sqlite3_close(db);  
  7.         this->close();  
  8.   
  9.     }  
  10.     printf("Connect success\n");  

    sqlite3_open()函数会打开一个数据库文件,当这个文件不存在则创建。下面是创建一个表格的代码。

[cpp]  view plain  copy
  1. void MainWindow::on_pushButton_ct_clicked()  
  2. {  
  3.     const char *sSQL = "create table users ("  
  4.                        "id integer PRIMARY KEY AUTOINCREMENT, "  
  5.                        "name varchar(40) NOT NULL, "  
  6.                        "age integer NOT NULL, "  
  7.                        "birthday datetime NOT NULL, "  
  8.                        "email varchar(40) NOT NULL);";  
  9.     //执行建表SQL  
  10.     int ret = sqlite3_exec(db, sSQL, NULL, 0, &pErrMsg);  
  11.     if (ret != SQLITE_OK)  
  12.     {  
  13.         fprintf(stderr, "SQL create error: %s\n", pErrMsg);  
  14.         sqlite3_free(pErrMsg); //be supposed  
  15.         return;  
  16.     }  
  17.   
  18.     rows = 0;  
  19.     index = 0;  
  20.     printf("Datebase table creator success!!\n");  
  21. }  

    使用sqlite3_exec()函数可以执行一条数据库指令,函数有5个参数,第一个是打开的数据库索引,第二个是要执行的语句,第三个是回调函数,当成功执行数据库语句后就会调用这个函数,第四个是传递给回调函数的参数,第五个是用来存储错误信息。这里创建了一个users表格,其有5列数据,第一列为id,设为主键。创建表格成功后,将表格的行数rows,当前查询的行号置零。接下来是插入一行数据的指令,代码如下。

[cpp]  view plain  copy
  1. void MainWindow::on_pushButton_ic_clicked()  
  2. {  
  3.     rows++;  
  4.   
  5.     QByteArray qb = QString("insert into users values"  
  6.                             "(%1, 'ws_%2', %3, '1989-5-4', '[email protected]');")  
  7.                             .arg(rows).arg(rows).arg(20+rows).toLatin1();  
  8.     const char *sSQL = qb.data();  
  9.     //执行插入数据  
  10.     int ret = sqlite3_exec(db, sSQL, NULL, 0, &pErrMsg);  
  11.     if (ret != SQLITE_OK)  
  12.     {  
  13.         fprintf(stderr, "SQL insert error: %s\n", pErrMsg);  
  14.         sqlite3_free(pErrMsg); //be supposed  
  15.         return;  
  16.     }  
  17.     ui->horizontalSlider->setMaximum(rows);  
  18.     printf("Datebase insert success!\n");  
  19. }  

    这里,将id号赋值为行号,姓名为"ws_行号",年龄为"20+行号",然后剩下两个参数固定,由于创建表格与插入数据都不需要调用回调函数,所以这里sqlite3_exec() 函数的第三个和第四个参数分别设置为NULL和零。接下来是查询语句,代码如下。

[cpp]  view plain  copy
  1. void MainWindow::on_pushButton_sp_clicked()  
  2. {  
  3.     if(index == 0)  index = 1;  
  4.     if(index > 1)   index--;  
  5.     QByteArray qb = QString("select * from users where id=%1").arg(index).toLatin1();  
  6.     const char *sSQL = qb.data();  
  7.     //执行查询操作  
  8.     int ret = sqlite3_exec(db, sSQL, _sql_callback, ui, &pErrMsg);  
  9.     if (ret != SQLITE_OK)  
  10.     {  
  11.         fprintf(stderr, "SQL error: %s\n", pErrMsg);  
  12.         sqlite3_free(pErrMsg);  
  13.         return;  
  14.     }  
  15.     ui->horizontalSlider->setValue(index);  
  16.     printf("Datebase inquire success!!\n");  
  17. }  

    这里将id号作为查询条件,执行了数据库的查询操作,查询的结果可以通过回调函数来读出,如果查询的为多行,则回调函数会被多次顺序调用。这里的回调函数为_sql_callback(),其中传递给回调函数的指针为ui指针。下面看回调函数的定义。

[cpp]  view plain  copy
  1. int MainWindow::_sql_callback(void *p, int argc, char **argv, char **szColName)  
  2. {  
  3.     Ui::MainWindow *ui = (Ui::MainWindow*)p;  
  4.     printf("Select argc:%d\n", argc);  
  5.   
  6.     ui->textEdit->clear();  
  7.     for (int i = 0; i < argc; i++)  
  8.     {  
  9.         ui->textEdit->append(QString("Property :%1, Value :%2").arg(szColName[i]).arg(argv[i]));  
  10.     }  
  11.   
  12.     return 0;  
  13. }  

    回调函数的参数中,p指针为传入的参数,即上面传入的ui指针,使用时要先将其强制转换。argc参数表示查询的一行数据有多少项,szColName指向该项数据的属性名,argv指向该项数据的值。这里将其显示到ui界面的textEdit控件上。下面来看删除行的操作,代码如下。

[cpp]  view plain  copy
  1. void MainWindow::on_pushButton_dc_clicked()  
  2. {  
  3.     if(rows > 0)  rows--;  
  4.     else{  
  5.         printf("No more row..\n");  
  6.         return;  
  7.     }  
  8.   
  9.     QByteArray qb = QString("delete from users where id=%1").arg(rows).toLatin1();  
  10.     const char *sSQL = qb.data();  
  11.     //delete row  
  12.     int ret = sqlite3_exec(db, sSQL, NULL, 0, &pErrMsg);  
  13.     if (ret != SQLITE_OK)  
  14.     {  
  15.         fprintf(stderr, "SQL insert error: %s\n", pErrMsg);  
  16.         sqlite3_free(pErrMsg); //be supposed  
  17.         return;  
  18.     }  
  19.     ui->horizontalSlider->setMaximum(rows);  
  20.     printf("Datebase insert success!\n");  
  21. }  

    删除行时,调用的命令为"delete from users where id=n",删除一行后,应将行数减一,这里行数是通过ui控件的horizontalSlider 来表示的。接下来是删除表格的命令,代码如下。

[cpp]  view plain  copy
  1. void MainWindow::on_pushButton_dt_clicked()  
  2. {  
  3.     const char *sSQL = "drop table users";  
  4.   
  5.     //delete table  
  6.     int ret = sqlite3_exec(db, sSQL, NULL, 0, &pErrMsg);  
  7.     if (ret != SQLITE_OK)  
  8.     {  
  9.         fprintf(stderr, "SQL delete error: %s\n", pErrMsg);  
  10.         sqlite3_free(pErrMsg); //be supposed  
  11.         return;  
  12.     }  
  13.   
  14.     rows = 0;  
  15.     index = 0;  
  16.     printf("Datebase table delete success!!\n");  
  17. }  

    删除表格的命令比较简单,为“drop table 表名”。最后来张在开发板上运行的图片。



    运行时,会通过串口打印命令执行的状态。如果启动应用时,表格已经存在,这个时候,为了是“查询下一条”这个按钮可以执行往下查询数据的命令,应该将表格的最大行数读出来,作为查询的参考条件。查询表格行数的命令是“select count(*) from 表名”,下面是查询表格最大行数的代码。

[cpp]  view plain  copy
  1. int MainWindow::sql_getrows(QString table)  
  2. {  
  3.     sqlite3_stmt *stat;  
  4.     QByteArray qb = QString("select count(*) from %1").arg(table).toLatin1();  
  5.     const char *sSQL = qb.data();  
  6.   
  7.     int ret = sqlite3_prepare_v2(db, sSQL, -1, &stat, 0);  
  8.     if (ret != SQLITE_OK)  
  9.     {  
  10.         fprintf(stderr, "SQL error: %s\n""prepare_v2");  
  11.         return 0;  
  12.     }  
  13.   
  14.     int count=0;  
  15.     if(sqlite3_step(stat)==SQLITE_ROW)  
  16.     {  
  17.         count=sqlite3_column_int(stat, 0);  
  18.     }  
  19.     sqlite3_finalize(stat); //perpare will lock the db, this unlock the db  
  20.   
  21.     return count;  
  22. }

你可能感兴趣的:(qt,qt,sql)