linux下C语言编程操作数据库(sqlite3)

来源:互联网 发布:日本球员 中超 知乎 编辑:程序博客网 时间:2024/05/16 10:49

前言:C语言中通过调用 sqlite 的函数接口来实现对数据库的管理(创建数据库、创建表格、插入数据、查询、数据、删除数据等),掌握sqlite数据库的语法,以及sqlite提供的函数接口,那么在linux下C语言编程操作数据库就变得简单了。

   Centos系统一般默认是没有安装sqlite3数据库的,所以我们要到其官网下载,我下载的版本是 sqlite-3.6.16.tar.gz  

[zoulei@CentOS sqlite]$ wget http://www.sqlite.org/sqlite-3.6.16.tar.gz
   进入下载目录,解压文件sqlite-3.6.16.tar.gz解压后生成sqlite-3.6.16目录. cd 进入sqlite-3.6.16

[zoulei@CentOS sqlite]$ tar -xzvf sqlite-3.6.16.tar.gz[zoulei@CentOS sqlite]$ cd sqlite-3.6.16[zoulei@CentOS sqlite-3.6.16]$

执行配置脚本,生成相关文件之后使用make命令编译

[zoulei@CentOS sqlite-3.6.16]$ ./configure[zoulei@CentOS sqlite-3.6.16]$ make[zoulei@CentOS sqlite-3.6.16]$ sudo make install
安装完成之后会在sqlite-3.6.16目录下生成sqlite3等文件

在linux下sqlite3具体怎么操作,可以参考这篇博客:点击打开链接

看代码:sqlite.c

/********************************************************************************* *      Copyright:  (C) 2017 zoulei *                  All rights reserved. * *       Filename:  insert.c *    Description:  This file i * *        Version:  1.0.0(2017年06月22日) *         Author:  zoulei <zoulei121@gmail.com> *      ChangeLog:  1, Release initial version on "2017年06月22日 19时31分12秒" * ********************************************************************************/#include <stdio.h>#include <stdlib.h>#include "sqlite3.h"#define _DEBUG_int main(int argc, char**argv){     sqlite3 *db=NULL;     int len;     int i=0;     int nrow=0;     int ncolumn = 0;     char *zErrMsg =NULL;     char **azResult=NULL; //二维数组存放结果     /* 打开数据库 */     len = sqlite3_open("user",&db);     if( len )     {        /*  fprintf函数格式化输出错误信息到指定的stderr文件流中  */        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));//sqlite3_errmsg(db)用以获得数据库打开错误码的英文描述。        sqlite3_close(db);        exit(1);     }     else printf("You have opened a sqlite3 database named user successfully!\n");     /* 创建表 */     char *sql = " CREATE TABLE SensorData(\         ID INTEDER PRIMARY KEY,\         SensorID INTEGER,\         siteNum INTEGER,\         Time VARCHAR(12),\         SensorParameter REAL\         );" ;      sqlite3_exec(db,sql,NULL,NULL,&zErrMsg);#ifdef _DEBUG_      printf("%s\n",zErrMsg);      sqlite3_free(zErrMsg);#endif      /*插入数据  */      char*sql1 ="INSERT INTO 'SensorData'VALUES(NULL,1,2,201430506201,13.5);";      sqlite3_exec(db,sql1,NULL,NULL,&zErrMsg);      char*sql2 ="INSERT INTO 'SensorData'VALUES(NULL,3,4,201530506302,14.5);";      sqlite3_exec(db,sql2,NULL,NULL,&zErrMsg);      char*sql3 ="INSERT INTO 'SensorData'VALUES(NULL,5,6,201630506413,18.6);";      sqlite3_exec(db,sql3,NULL,NULL,&zErrMsg);      /* 查询数据 */      sql="select *from SensorData";      sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );      printf("nrow=%d ncolumn=%d\n",nrow,ncolumn);      printf("the result is:\n");      for(i=0;i<(nrow+1)*ncolumn;i++)        {          printf("azResult[%d]=%s\n",i,azResult[i]);        }     /* 删除某个特定的数据 */      sql="delete from SensorData where SensorID = 1 ;";      sqlite3_exec( db , sql , NULL , NULL , &zErrMsg );#ifdef _DEBUG_      printf("zErrMsg = %s \n", zErrMsg);      sqlite3_free(zErrMsg);#endif      /* 查询删除后的数据 */      sql = "SELECT * FROM SensorData ";      sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );      printf( "row:%d column=%d\n " , nrow , ncolumn );      printf( "After deleting , the result is : \n" );      for( i=0 ; i<( nrow + 1 ) * ncolumn ; i++ )      {            printf( "azResult[%d] = %s\n", i , azResult[i] );      }      sqlite3_free_table(azResult);#ifdef _DEBUG_   printf("zErrMsg = %s \n", zErrMsg);   sqlite3_free(zErrMsg);#endif      sqlite3_close(db);      return 0;}

 代码分析:

其实操作数据库无非就是如何调用sqlite3提供的API,以及如何使用相应的语句操作sqlite3数据库进行增,删,改,查等。那么下面我们着重分析

一下sqlite3提供的函数接口。

1.打开数据库函数接口

原型:int sqlite3_open(const char * filename, sqlite3 **ppDb);

int sqlite3_open(  const char *filename,   /* Database filename (UTF-8) */  sqlite3 **ppDb          /* OUT: SQLite db handle */);

用这个函数开始数据库操作。需要传入两个参数,一是数据库文件名,比如:我的虚拟机~/sqlite/路径下的user文件,文件名不需要一定存在,如果此文件不存在,sqlite会自动建立它。如果它存在,就尝试把它当数据库文件来打开。二是sqlite3**,即前面提到的关键数据结构。这个结构底层细节如何,不需要管它。函数返回值表示操作是否正确,如果是SQLITE_OK则表示操作正常。相关的返回值sqlite定义了一些宏。具体这些宏的含义可以参考sqlite3.h 文件。

2.关闭数据库函数接口

原型:int sqlite3_close(sqlite3**ppDb);

ppDb为我们使用sqlite3_open()函数打开的数据库链接(对应我写的程序中的db变量)。

3.执行sql语句函数接口

原型:int sqlite3_exec(sqlite3*,const char*sql,sqlite_callback,void*data,char**errmsg);

int sqlite3_exec(  sqlite3*,                     /* An open database */  const char *sql,              /* SQL to be executed */  sqlite_callback,              /* Callback function */  void *,                       /* 1st argument to callback function */  char **errmsg                 /* Error msg written here */);

这就是执行一条sql 语句的函数,

第1个参数不再说了,是前面open函数得到的指针。说了是关键数据结构。
第2个参数const char*sql是一条sql 语句,以\0结尾。
第3个参数sqlite3_callback 是回调,当这条语句执行之后,sqlite3会去调用你提供的这个函数。通常设为NULL。
第4个参数void*是你所提供的指针,你可以传递任何一个指针参数到这里,这个参数最终会传到回调函数里面,如果不需要传递指针给回调函数,可以填NULL。
第5个参数char** errmsg 是错误信息。注意是指针的指针。sqlite3里面有很多固定的错误信息。执行sqlite3_exec 之后,执行失败时可以查阅这个指针(直接 printf("zErrMsg = %s \n", zErrMsg)得到一串字符串信息,这串信息告诉你错在什么地方。sqlite3_exec函数通过修改你传入的指针的指针,把你提供的指针指向错误提示信息,这样sqlite3_exec函数外面就可以通过这个char*得到具体错误提示。

************************************************************************************************************************

说明:通常,sqlite3_callback 和它后面的void*这两个位置都可以填NULL。填NULL表示你不需要回调。比如你做insert 操作,做delete操作,就没有必要使用回调。而当你做select 时,就要使用回调,因为sqlite3 把数据查出来,得通过回调告诉你查出了什么数据。虽然回调显得代码整齐,但有时候你还是想要非回调的select 查询。这可以通过sqlite3_get_table 函数做到。

原型:sqlite3_get_table(sqlite3*db,const char*zsql,char***pazResult,int*nrow,int*ncolumn,char**zErrmsg);

int sqlite3_get_table(  sqlite3 *db,          /* An open database */  const char *zSql,     /* SQL to be evaluated */  char ***pazResult,    /* Results of the query */  int *pnRow,           /* Number of result rows written here */  int *pnColumn,        /* Number of result columns written here */  char **pzErrmsg       /* Error msg written here */);void sqlite3_free_table(char **result);

第1个参数不再多说,看前面的例子。
第2个参数是sql 语句,跟sqlite3_exec 里的sql 是一样的。是一个很普通的以\0结尾的char*字符串。
第3个参数是查询结果,它依然一维数组(不要以为是二维数组,更不要以为是三维数组)。它内存布局是:字段名称,后面是紧接着是每个字段值。
第4个参数是查询出多少条记录(即查出多少行,不包括字段名那行)。
第5个参数是多少个字段(多少列)。
第6个参数是错误信息,跟前面一样,这里不多说了。

pazResult返回的字符串数量实际上是(*pnRow+1)*(*pnColumn),因为前(*pnColumn)个是字段名。

注意:如果提供 了errmsg,用来创建错误消息的内存是在堆上分布的。 故在调用后,应该检查一下是否为null值,如果有错误发生,使用sqlite3_free()释放errmsg占用的内存。

*************************************************************************************************************************************************************************

编译运行

[zoulei@CentOS sqlite]$ gcc sqlite.c -o sqlite -l sqlite3

[zoulei@CentOS sqlite]$ ./sqlite
You have opened a sqlite3 database named user successfully!
table SensorData already exists
nrow=3 ncolumn=5
the result is:
azResult[0]=ID
azResult[1]=SensorID
azResult[2]=siteNum
azResult[3]=Time
azResult[4]=SensorParameter
azResult[5]=(null)
azResult[6]=1
azResult[7]=2
azResult[8]=201430506201
azResult[9]=13.5
azResult[10]=(null)
azResult[11]=3
azResult[12]=4
azResult[13]=201530506302
azResult[14]=14.5
azResult[15]=(null)
azResult[16]=5
azResult[17]=6
azResult[18]=201630506413
azResult[19]=18.6
zErrMsg = (null)
row:2 column=5
 After deleting , the result is :
azResult[0] = ID
azResult[1] = SensorID
azResult[2] = siteNum
azResult[3] = Time
azResult[4] = SensorParameter
azResult[5] = (null)
azResult[6] = 3
azResult[7] = 4
azResult[8] = 201530506302
azResult[9] = 14.5
azResult[10] = (null)
azResult[11] = 5
azResult[12] = 6
azResult[13] = 201630506413
azResult[14] = 18.6
zErrMsg = (null)

从程序输出结果就可以看出,在删除数据前,我们有三条记录,删除数据后我们发现,数据库内记录少了。从而实现了我们的删除数据目的。

****************************************************************************************************************************************************************************************

注意:这里我们可以看到,azResult 的前面 5 个数据正好是我们的表 SensorData 的列属性,之后才是我们要查询的数据。所以我们

的程序中才有 i<( nrow + 1 ) * ncolumn  的判断条件:
  for( i=0 ; i<( nrow + 1 ) * ncolumn ; i++ )
  printf( "azResult[%d] = %s/n", i , azResult[i] );

 输出中有 zErrMsg = (null) 这样的字句,这是 zErrMsg 保留的错误信息,正如你所看到的,zErrMsg 为空,表明在执行过程中没有错误信息。

***************************************************************************************************************************************************************************

遇到的问题:

[zoulei@CentOS sqlite]$ gcc sqlite.c -o sqlite
/tmp/cccHlOCK.o: In function `main':
opensqlite.c:(.text+0x21): undefined reference to `sqlite3_open'
opensqlite.c:(.text+0x38): undefined reference to `sqlite3_errmsg'
opensqlite.c:(.text+0x5f): undefined reference to `sqlite3_close'
opensqlite.c:(.text+0x83): undefined reference to `sqlite3_close'
collect2: ld 返回 1

问题解决:

出现上述问题是因为没有找到库文件的问题。
由于用到了用户自己的库文件,所以应该指明所用到的库,我们可以这样编译:

[zoulei@CentOS sqlite]$ gcc sqlite.c -o sqlite -l sqlite3

通过find命令找出sqlite3依赖的库:

[zoulei@CentOS sqlite-3.6.16]$ find -name "libsqlite3.so"
./.libs/libsqlite3.so
[zoulei@CentOS sqlite-3.6.16]$ cd ./.libs
[zoulei@CentOS .libs]$ ls


所以用 -l sqlite3 选项就可以了(由于编译生成的库文件是 libsqlite3.so.0.8.6 等,去掉前面的lib和后面的版本标志,就剩下 sqlite3 了所以是 -l sqlite3 )




阅读全文
0 0