Sqlite3之C++开发常用API总结

Sqlite3之C++开发常用API总结

注:此篇博客摘抄总结于几个博客,尽可能全面地讲解C++开发过程中涉及的API相关的知识。

使用流程

要使用sqlite,需要从sqlite官网下载到三个文件,分别为sqlite3.lib,sqlite3.dll,sqlite3.h,然后再在自己的工程中配置好头文件和库文件,同时将dll文件放到当前目录下,就完成配置可以使用sqlite了。引用例子如下:

extern "C"
{
  #include "./sqlite3.h" 
  /*
  在 C++ 里使用一段 C 的代码,必须要用 extern “C” 括起来。
  C++ 跟 C虽然语法上有重叠,但是它们是两个不同的东西,内存里的布局是完全不同的,在C++编译器里不用extern “C”括起C代码,会导致编译器不知道该如何为 C 代码描述内存布局。
  可能在 sqlite3.c 里已经把整段代码都 extern “C” 括起来了,但是此处再次声明一次避免意外情况。
  */
};

int main(int, char**)
{
  return 0;
  /*
  sqlite提供的是一些C函数接口,你可以用这些函数操作数据库。
  通过使用这些接口,传递一些标准 sql 语句(以 char * 类型)给 sqlite 函数即可操作数据库。
  */
}

使用的过程根据使用的函数大致分为如下几个过程:

  • sqlite3_open()
  • sqlite3_exec()
  • sqlite3_close()

  • sqlite3_open()
  • sqlite3_prepare()
  • sqlite3_step()
  • sqlite3_column()
  • sqlite3_finalize()
  • sqlite3_close()

这几个过程是概念上的说法,而不完全是程序运行的过程,如sqlite3_column()表示的是对查询获得一行里面的数据列进行的各种操作统称,实际上在sqlite中并不存在这个函数。

sqlite3_open()

在操作数据库之前,首先要打开数据库。这个函数打开一个sqlite数据库文件的连接并且返回一个数据库连接对象。这个操作同时程序中的第一个调用的 sqlite函数,同时也是其他sqlite api的先决条件。许多的sqlite接口函数都需要一个数据库连接对象的指针作为它们的第一个参数。
函数定义:

 int sqlite3_open(

  const char *filename,   /* Database filename (UTF-8) */

  sqlite3 **ppDb          /* OUT: SQLite db handle */

);

int sqlite3_open16(

  const void *filename,   /* Database filename (UTF-16) */

  sqlite3 **ppDb          /* OUT: SQLite db handle */

);

int sqlite3_open_v2(

  const char *filename,   /* Database filename (UTF-8) */

  sqlite3 **ppDb,         /* OUT: SQLite db handle */

  int flags,              /* Flags */

  const char *zVfs        /* Name of VFS module to use */

);

假如这个要被打开的数据文件不存在,则一个同名的数据库文件将被创建。

参数说明:

  • filename:需要被打开的数据库文件的文件名,在sqlite3_open和sqlite3_open_v2中这个参数采用UTF-8编码,而在sqlite3_open16中则采用UTF-16编码。
  • ppDb:一个数据库连接句柄被返回到这个参数,即使发生错误。唯一的一场是如果sqlite不能分配内存来存放sqlite对象,ppDb将会被返回一个NULL值。
  • flags:作为数据库连接的额外控制的参数,可以是SQLITE_OPEN_READONLY,SQLITE_OPEN_READWRITE和SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE中的一个,用于控制数据库的打开方式,可以和SQLITE_OPEN_NOMUTEX,SQLITE_OPEN_FULLMUTEX, SQLITE_OPEN_SHAREDCACHE,以及SQLITE_OPEN_PRIVATECACHE结合使用,具体的详细情况可以查阅文档。

返回值说明:
如果sqlite数据库被成功打开(或创建),将会返回SQLITE_OK,否则将会返回错误码。Sqlite3_errmsg()或者sqlite3_errmsg16可以用于获得数据库打开错误码的英文描述,这两个函数定义为:

const char *sqlite3_errmsg(sqlite3*);

const void *sqlite3_errmsg16(sqlite3*);

Sqlite3_prepare()

这个函数将sql文本转换成一个准备语句(prepared statement)对象,同时返回这个对象的指针。这个接口需要一个数据库连接指针以及一个要准备的包含SQL语句的文本。它实际上并不执行(evaluate)这个SQL语句,它仅仅为准备执行这个sql语句。

函数定义(仅列出UTF-8的):

int sqlite3_prepare(

  sqlite3 *db,            /* Database handle */

  const char *zSql,       /* SQL statement, UTF-8 encoded */

  int nByte,              /* Maximum length of zSql in bytes. */

  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */

  const char **pzTail     /* OUT: Pointer to unused portion of zSql */

);

int sqlite3_prepare_v2(

  sqlite3 *db,            /* Database handle */

  const char *zSql,       /* SQL statement, UTF-8 encoded */

  int nByte,              /* Maximum length of zSql in bytes. */

  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */

  const char **pzTail     /* OUT: Pointer to unused portion of zSql */

);

参数说明:

  • db:数据指针。
  • zSql:sql语句,使用UTF-8编码。
  • nByte:如果nByte小于0,则函数取出zSql中从开始到第一个0终止符的内容;如果nByte不是负的,那么它就是这个函数能从zSql中读取的字节数的最大值。如果nBytes非负,zSql在第一次遇见’/000/或’u000’的时候终止。
  • pzTail:上面提到zSql在遇见终止符或者是达到设定的nByte之后结束,假如zSql还有剩余的内容,那么这些剩余的内容被存放到pZTail中,不包括终止符。
  • ppStmt:能够使用sqlite3_step()执行的编译好的准备语句指针,如果错误发生,它被置为NULL,比如输入的文本不包括sql语句。调用过程必须负责在编译好的sql语句完成使用后使用sqlite3_finalize()删除它。

返回值说明:
如果执行成功,则返回SQLITE_OK,否则返回一个错误码。推荐在现在任何的程序中都使用sqlite3_prepare_v2这个函数,sqlite3_prepare只是用于前向兼容。

备注:

  1. 准备语句(prepared statement)对象
typedef struct sqlite3_stmt sqlite3_stmt;

准备语句(prepared statement)对象一个代表一个简单SQL语句对象的实例,这个对象通常被称为“准备语句”或者“编译好的SQL语句”或者就直接称为“语句”。

语句对象的生命周期经历这样的过程:

  • 使用sqlite3_prepare_v2或相关的函数创建这个对象
  • 使用sqlite3_bind_*()给宿主参数(host parameters)绑定值
  • 通过调用sqlite3_step一次或多次来执行这个sql
  • 使用sqlite3_reset()重置这个语句,然后回到第2步,这个过程做0次或多次
  • 使用sqlite3_finalize()销毁这个对象

在sqlite中并没有定义sqlite3_stmt这个结构的具体内容,它只是一个抽象类型,在使用过程中一般以它的指针进行操作,而sqlite3_stmt类型的指针在实际上是一个指向Vdbe的结构体的指针。

sqlite3_stmt *作为辅助的数据类型:sqlite3_stmt * ,因其已被解析的原因,可以往这个语句里插入二进制数据(也就是操作二进制数据需要使用sqlite3_stmt *)。当然,把二进制数据插到 sqlite3_stmt 结构里可不能直接 memcpy ,也不能像 std::string 那样用 + 号。必须用 sqlite 提供的函数来插入。
注意,要插入二进制,前提是这个表的字段的类型是 blob 类型。

  1. 宿主参数(host parameters)

在传给sqlite3_prepare_v2()的sql的语句文本或者它的变量中,满足如下模板的文字将被替换成一个参数:

  • ?
  • ?NNN,NNN代表数字
  • :VVV,VVV代表字符
  • @VVV
  • $VVV

在上面这些模板中,NNN代表一个数字,VVV代表一个字母数字标记符(例如:222表示名称为222的标记符),sql语句中的参数(变量)通过上面的几个模板来指定,如

“select ? from ? 

“这个语句中指定了两个参数,sqlite语句中的第一个参数的索引值是1,这就知道这个语句中的两个参数的索引分别为1和2,使用”?”的话会被自动给予索引值,而使用”?NNN”则可以自己指定参数的索引值,它表示这个参数的索引值为NNN。”:VVV”表示一个名为”VVV”的参数,它也有一个索引值,被自动指定。
可以使用sqlite3_bind_*()来给这些参数绑定值。

sqlite3_bind()_*()

sqlite3_bind()_*()是一系列值绑定函数,值绑定就是在SQL语句预编译时把一些参数使用占位符(这里是?号)来代替,然后与程序中的变量进行绑定,类似于字符串的格式化。

在sqlite3_prepare_v2()输入的SQL语句的文本中,宿主参数将会被替换掉,说的直白一些,在sqlite3_prepare_v2()中的“?”号就是匿名参数,从第一个问号出现往后的索引默认是1,往后以此类推。而“?NNN”是为匿名参数指定索引,你可以这样写“?1” , "?2"等,而:VVV, @VVV, VVV这些就是有名参数了,VVV就是参数的名字。

//BLOB是数据库中存储大数据的一种数据类型,使用二进制的形式来存储数据
SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));    
 
//绑定double类型数据
SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);    
 
//绑定一个32位整型值
SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
 
//绑定一个64位整型值
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
 
//绑定一个NULL的值(在数据库中可以为NULL)
SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
 
//绑定一个UTF-8编码的字符串,第四个参数是绑定字符串的长度,如果为负值则传多少绑多少
SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
 
//绑定一个UTF-16编码的字符串,第四个参数是绑定字符串的长度,如果为负值则传多少绑多少
SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));    
 
//绑定sqlite3_value结构体类型的值,sqlite3_value结构体可以保存任意格式的数据
SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);    
 
//绑定一个任意长度的BLOB类型的二进制数据且所有字节被置0,第3个参数是字节长度,其用处是创建一个大的BLOB对象,之后通过BLOB接口函数进行更新
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);

参数说明:

  • sqlite3_bind_*()的第一个参数是含有上述占位符预编译后的语句指针,也就是sqlite3_stmt的对象。

  • sqlite3_bind_*()的第二个参数是SQL语句中参数的索引,例如第一个参数的索引值是1,那么就传1。匿名参数的索引是从1开始往后递增的,而有参数名称的可以通过sqlite3_bind_parameter_index()接口传入参数名称来获取该参数的索引。

  • sqlite3_bind_*()的第三个参数是要绑定的值。

  • sqlite3_bind_blob(), sqlite3_bind_text()和sqlite3_bind_text16()这三个接口中还有有第四和第五个参数,第四个参数代表第三个参数“绑定值”的字节长度。第五个参数是一个指向内存管理回调函数的指针。

返回值说明:
这些绑定函数执行成功后回返回SQLITE_OK, 执行不成功的话回返回相应的错误代码。

sqlite3_bind_parameter_index()用法如下:

int index = sqlite3_bind_parameter_index(statement, "$brandidMin");

第一个参数是sqlite3_stmt的对象,而后边的参数是SQL参数名称,返回值就是该参数的索引。

sqlite3_step()

这个过程用于执行有前面sqlite3_prepare创建的准备语句。这个语句执行到结果的第一行可用的位置。如若继续前进到结果的第二行的话,只需再次调用sqlite3_setp()。持续调用sqlite3_setp()直到这个语句完成,那些不返回结果的语句(如:INSERT,UPDATE,或DELETE),sqlite3_step()只执行一次就返回。

函数定义:

int sqlite3_step(sqlite3_stmt*);

返回值说明:
函数的返回值基于创建sqlite3_stmt参数所使用的函数,假如是使用老版本的接口sqlite3_prepare()和sqlite3_prepare16(),返回值会是 SQLITE_BUSY, SQLITE_DONE, SQLITE_ROW, SQLITE_ERROR 或 SQLITE_MISUSE,而v2版本的接口sqlite3_prepare_v2()和sqlite3_prepare16_v2()则会同时返回这些结果码和扩展结果码。

当进行查询功能时,执行成功的返回值为SQLITE_ROW 而不是 SQLITE_OK,为可以循环执行sqlite3_step 函数,一次step查询出一条记录。直到返回值不为 SQLITE_ROW 时表示查询结束。

对所有V3.6.23.1以及其前面的所有版本,需要在sqlite3_step()之后调用sqlite3_reset(),在后续的sqlite3_ step之前。如果调用sqlite3_reset重置准备语句失败,将会导致sqlite3_ step返回SQLITE_MISUSE,但是在V3.6.23.1以后,sqlite3_step()将会自动调用sqlite3_reset。

int sqlite3_reset(sqlite3_stmt *pStmt);

sqlite3_reset用于重置一个准备语句对象到它的初始状态,然后准备被重新执行(重复使用 sqlite3_prepare 解析好的初始的 sqlite3_stmt 结构)。所有sql语句变量使用sqlite3_bind*绑定值,使用sqlite3_clear_bindings重设这些绑定。Sqlite3_reset接口重置准备语句到它代码开始的时候。sqlite3_reset并不改变在准备语句上的任何绑定值,那么这里猜测,可能是语句在被执行的过程中发生了其他的改变,然后这个语句将它重置到绑定值的时候的那个状态。

值得注意的是,在sqlite3_step (stmt)之前,调用bind绑定的的所有数据必须仍然存在而不能被被释放,否则就不能真正写入,即需要保证bind绑定的内容需要在step调用的时候存在而不被释放,例子如下:

{
  char * tmp_char = (char*)malloc (data_size);
  memcpy(tmp_char, data_buffer, data_size);
  sqlite3_bind_text (stmt, cols, tmp_char, data_size, SQLITE_STATIC);
  free (tmp_char);
  if(SQLITE_DONE == sqlite3_step (stmt)) //写入失败,因为sqlite3_bind_text()绑定的tmp_char已被释放
  {
    sqlite3_reset (stmt);
  }
}
    
{
  char * tmp_char = (char*)malloc (data_size);
  memcpy(tmp_char, data_buffer, data_size);
  sqlite3_bind_text (stmt, cols, tmp_char, data_size, SQLITE_STATIC);
  if(SQLITE_DONE == sqlite3_step (stmt)) //写入成功,因为sqlite3_bind_text()绑定的tmp_char未被释放
  {
    sqlite3_reset (stmt);
  }
  free (tmp_char);
}

sqlite3_column()

这个过程从执行sqlite3_step()执行一个准备语句得到的结果集的当前行中返回一个列。每次sqlite3_step得到一个结果集的列停下后,这个过程就可以被多次调用去查询这个行的各列的值。对列操作是有多个函数,均以sqlite3_column为前缀。

const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);

int sqlite3_column_bytes(sqlite3_stmt*, int iCol);

int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);

double sqlite3_column_double(sqlite3_stmt*, int iCol);

int sqlite3_column_int(sqlite3_stmt*, int iCol);

sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);

const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);

const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);

int sqlite3_column_type(sqlite3_stmt*, int iCol);

sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);

说明:
第一个参数为从sqlite3_prepare返回来的prepared statement对象的指针,第二参数指定这一行中的想要被返回的列的索引。最左边的一列的索引号是0,行的列数可以使用sqlite3_colum_count()获得。

这些过程会根据情况去转换数值的类型,sqlite内部使用sqlite3_snprintf()去自动进行这个转换,下面是关于转换的细节表:

内部类型请求的类型转换
NULLINTEGER结果是0
NULLFLOAT结果是0.0
NULLTEXT结果是NULL
NULLBLOB结果是NULL
INTEGERFLOAT从整形转换到浮点型
INTEGERTEXT整形的ASCII码显示
INTEGERBLOB同上
FLOATINTEGER浮点型转换到整形
FLOATTEXT浮点型的ASCII显示
FLOATBLOB同上
TEXTINTEGER使用atoi()
TEXTFLOAT使用atof()
TEXTBLOB没有转换
BLOBINTEGER先到TEXT,然后使用atoi
BLOBFLOAT先到TEXT,然后使用atof
BLOBTEXT如果需要的话添加0终止符

注:BLOB数据类型是指二进制的数据块,比如要在数据库中存放一张图片,这张图片就会以二进制形式存放,在sqlite中对应的数据类型就是BLOB

int sqlite3_column_bytes(sqlite3_stmt*, int iCol)
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol)

两个函数返回对应列的内容的字节数,这个字节数不包括后面类型转换过程中加上的0终止符。

下面是几个最安全和最简单的使用策略

  • 先sqlite3_column_text() ,然后sqlite3_column_bytes()
  • 先sqlite3_column_blob(),然后sqlite3_column_bytes()
  • 先sqlite3_column_text16(),然后sqlite3_column_bytes16()

sqlite3_exec()

int sqlite3_exec(
  sqlite3* *ppDb,                                /* An open database */

  const char *sql,                               /* SQL to be evaluated */

  int (*callback) (void*, int, char**, char**),  /* Callback function */

  void * parame,                                 /* 1st argument to callback */

  char **errmsg                                  /* Error msg written here */
  
  );

参数说明:

  • ppDb:一个数据库连接句柄参数。
  • sql:一条要执行的 sql 语句,以/0结尾。
  • callback:回调函数,当这条语句执行之后,sqlite3会去调用你提供的这个函数
  • parame:指定任意指针参数,这个参数会自动传给回调函数,如果不需要传递指针给回调函数,可以填NULL。
  • errmsg:错误信息,注意是指针的指针。sqlite3里面有很多固定的错误信息。执行 sqlite3_exec 之后,执行失败时可以查阅这个指针(直接 printf(“%s/n”,errmsg))得到一串字符串信息,这串信息告诉你错在什么地方。sqlite3_exec函数通过修改你传入的指针的指针,把你提供的指针指向错误提示信息,这样sqlite3_exec函数外面就可以通过这个 char*得到具体错误提示。

补充说明:
通常,sqlite3_callback 和它后面的 void * 这两个位置都可以填 NULL。填NULL表示你不需要回调。比如你做insert 操作,做 delete 操作,就没有必要使用回调。而当你做 select 时,就要使用回调,因为 sqlite3 把数据查出来,得通过回调告诉你查出了什么数据。

代码示例:

#include "stdafx.h"
#include "sqlite3.h"

static int callback(void *NotUsed, int argc, char **argv, char **azColName) /*回调函数*/
{
  /*
  第一个参数通过sqlite3_exec的第第四个参数传入的
  第二个参数是结果行的列数
  第三个参数是行中列数据的指针
  第四个参数是行中列名称的指针
  */
    int i;
    for(i = 0; i < argc; i++) {
       printf("%s = %s/n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    printf("/n");
    return 0;
}

#define CHECK_RC(rc, szInfo, szErrMsg, db) if(rc != SQLITE_OK) / /*异常处理*/
{
  printf("%s error!/n", szInfo); /
  printf("%s/n", szErrMsg); /
  sqlite3_free(szErrMsg); /
  sqlite3_close(db); /
  return 0;
}

int _tmain(int argc, _TCHAR* argv[]) /*调用过程*/
{
    sqlite3 *db;
    char *dbPath="f:/test.db";
    char *szErrMsg = 0;


    int rc= sqlite3_open(dbPath, &db);
    CHECK_RC(rc, "open database", db);
    char *szSql = "create table UserInfo(ID int primary key, UserName char, PassWord char);";

    rc = sqlite3_exec(db, szSql, 0, 0, &szErrMsg);
    CHECK_RC(rc, "create table", szErrMsg, db);

    rc=sqlite3_exec(db, "insert into UserInfo(ID, UserName, PassWord) values(1, 'kfqcome', '123456')", 0, 0, &szErrMsg);
    CHECK_RC(rc, "insert info", szErrMsg, db);

    rc=sqlite3_exec(db, "insert into UserInfo(ID,UserName,PassWord) values(2, 'miss wang', '654321')", 0, 0, &szErrMsg);
    CHECK_RC(rc, "insert info", szErrMsg,db);

    szSql="select * from UserInfo";
    rc = sqlite3_exec(db, szSql, callback, 0, &szErrMsg);
    CHECK_RC(rc, "query values", szErrMsg, db);


    sqlite3_close(db);
    getchar();
    return 0;
}

输出的结果:
ID = 1
UserName = kfqcome
PassWord = 123456

ID = 2
UserName = miss wang
PassWord = 654321

这里执行的sql语句用的是sqlite3_exec,它是前面几个函数的封装。
sqlite3_exec是sqlite3_prepare_v2,sqlite3_step()和sqlite3_finalize()的封装,能让程序多次执行sql语句而不要写许多重复的代码。

Sqlite3_exec接口执行0或多个UTF-8编码的,分号分割的sql语句,传到第二个参数中。如果sqlite3_exec的第三个参数回调函数指针不为空,那么它会为每个来自执行的SQL语句的结果行调用(也就是说回调函数会调用多次,上面例子中会返回2个结果行,因而会被执行2次),第4个参数是传给回调函数的第一个参数,如果回调函数指针为空,那么回调不会发生同时结果行被忽略。

如果在执行sql语句中有错误发生,那么当前的语句的执行被停止,后续的语句也被跳过。第五个参数不为空的时候,它被分配内存并写入了错误信息,所以在sqlite3_exec后面需要调用sqlite3_free去释放这个对象以防止内存泄露。

sqlite3_finalize

int sqlite3_finalize(sqlite3_stmt *pStmt);

这个过程销毁前面被sqlite3_prepare创建的准备语句,即sqlite3_stmt对象的析构操作,每个准备语句都必须使用这个函数去销毁以防止内存泄露。

在空指针上调用这个函数没有什么影响,同时可以准备语句的生命周期的任一时刻调用这个函数:在语句被执行前,一次或多次调用sqlite_reset之后,或者在sqlite3_step任何调用之后不管语句是否完成执行。

sqlite3_close

int sqlite3_close(sqlite3 **ppDb );

这个过程关闭前面使用sqlite3_open打开的数据库连接,任何与这个连接相关的准备语句必须在调用这个关闭函数之前被释放。

代码示例:

void MyTest::Add_Data() //该例子由我的同事zkh(EnName:snake)提供
{
    sqlite3_exec(db, "begin;", 0, 0, 0); //使用("begin;")作为参数处理大批量数据的操作语句

    sqlite3_stmt *pstmt;
    string strsql;                                                                //char sql[1024] = "insert into Table_Menu values(?,?);";
    strsql.format("insert into Table_Menu values('%s', ? , ? );", g_str.c_str()); //三列,g_str为有对应意义的全局变量

    ret = sqlite3_prepare_v2(db, strsql, strlen(strsql), &pstmt, NULL);
    if (ret == SQLITE_OK)
    {
        for (map<string, string>::iterator it = mapAllData.begin(); it != mapAllData.end(); it++)
        {

            string strIndex = it->first.c_str();
            string strText = it->second.c_str();
            strIndex = ASCII2UTF8(strIndex);
            strText = ASCII2UTF8(strText);

            sqlite3_bind_text(pstmt, 1, strIndex.c_str(), -1, NULL);
            sqlite3_bind_text(pstmt, 2, strText.c_str(), -1, NULL);

            if (sqlite3_step(pstmt) != SQLITE_DONE) //sqlite3_step()调用sqlite3_reset()
            {
                string strTest;
                strTest.format("db prepare fail, errcode[%d], errmsg[%s]\n", ret, sqlite3_errmsg(db));
            }
        }
    }
    else
    {
        string strTest;
        strTest.format("db prepare fail, errcode[%d], errmsg[%s]\n", ret, sqlite3_errmsg(db));
        sqlite3_close(db);
    }

    sqlite3_exec(db, "commit;", 0, 0, 0); //使用("commit;")作为参数提交存储之后的大量数据
    sqlite3_finalize(pstmt); //析构pstmt对象
    sqlite3_close(db);
}

性能优化

SQLite可以进行参数的配置,从而对性能进行调整,参数配置主要通过pragma指令来实现。
比如空间释放、磁盘同步、Cache大小等。

  1. auto_vacuum
PRAGMA auto_vacuum; 
PRAGMA auto_vacuum = 0 | 1;

查询或设置数据库的auto-vacuum标记。

正常情况下,当提交一个从数据库中删除数据的事务时,数据库文件不改变大小。未使用的文件页被标记并在以后的添加操作中再次使用。这种情况下可使用VACUUM命令释放删除得到的空间。

当开启auto-vacuum,当提交一个从数据库中删除数据的事务时,数据库文件自动收缩, (VACUUM命令在auto-vacuum开启的数据库中不起作用)。数据库会在内部存储一些信息以便支持这一功能,这使得数据库文件比不开启该选项时稍微大一些。

只有在数据库中未建任何表时才能改变auto-vacuum标记,试图在已有表的情况下修改会导致报错。

  1. cache_size
PRAGMA cache_size; 
PRAGMA cache_size = Number-of-pages; //建议改为8000

查询或修改SQLite一次存储在内存中的数据库文件页数。每页使用约1.5K内存,缺省默认的缓存大小是2000. 若需要使用改变大量多行的UPDATE或DELETE命令,并且不介意SQLite使用更多的内存的话,可以增大缓存以提高性能。

当使用cache_size pragma改变缓存大小时,改变仅对当前对话有效,当数据库关闭重新打开时缓存大小恢复到缺省大小。 要想永久改变缓存大小,使用default_cache_size pragma.

  1. case_sensitive_like
PRAGMA case_sensitive_like; 
PRAGMA case_sensitive_like = 0 | 1;

LIKE运算符的默认缺省行为是忽略字符的大小写。因此在缺省情况下’a’ LIKE 'A’的值为真。可以通过打开case_sensitive_like pragma来改变这一缺省行为。当启用case_sensitive_like,‘a’ LIKE 'A’为假而 ‘a’ LIKE 'a’依然为真。

  1. count_changes
PRAGMA count_changes; 
PRAGMA count_changes = 0 | 1;

查询或更改count-changes标记。正常情况下INSERT, UPDATE和DELETE语句不返回数据,当开启count-changes,返回插入,修改或删除的行数。返回的行数不包括由触发器产生的插入,修改或删除等改变的行数。

  1. page_size
PRAGMA page_size; 
PRAGMA page_size = bytes;

查询或设置page_size值,只有在未创建数据库时才能设置page-size。页面大小必须是2的整数倍且大于等于512小于等于8192。上限可以通过在编译时修改宏定义SQLITE_MAX_PAGE_SIZE的值来改变。上限的默认值是32768。

  1. synchronous
    如果有定期备份的机制,而且少量数据丢失可接受,用OFF。
PRAGMA synchronous; 
PRAGMA synchronous = FULL; (2) 
PRAGMA synchronous = NORMAL; (1) 
PRAGMA synchronous = OFF; (0)

查询或更改"synchronous"标记的设定。第一种形式(查询)返回整数值。当synchronous设置为FULL(2), SQLite数据库引擎在紧急时刻会暂停以确定数据已经写入磁盘。这使系统崩溃或电源出问题时能确保数据库在重起后不会损坏。FULL synchronous很安全但很慢。当synchronous设置为NORMAL,SQLite数据库引擎在大部分紧急时刻会暂停,但不像FULL模式下那么频繁。NORMAL模式下有很小的几率(但不是不存在)发生电源故障导致数据库损坏的情况。但实际上,在这种情况下很可能你的硬盘已经不能使用,或者发生了其他的不可恢复的硬件错误。设置为synchronous OFF(0)时,SQLite在传递数据给系统以后直接继续而不暂停。若运行SQLite的应用程序崩溃,数据不会损伤,但在系统崩溃或写入数据时意外断电的情况下数据库可能会损坏。另一方面,在synchronous OFF时,一些操作可能会快50倍甚至更多。
在SQLite2中,缺省值为NORMAL.而在SQLite3中修改为FULL.

  1. temp_store
PRAGMA temp_store; 
PRAGMA temp_store = DEFAULT; (0) 
PRAGMA temp_store = FILE; (1) 
PRAGMA temp_store = MEMORY; (2)

查询或更改"temp_store"参数的设置。当temp_store设置为DEFAULT(0),使用编译时的C预处理宏 TEMP_STORE来定义储存临时表和临时索引的位置。当设置为MEMORY(2),临时表和索引存放于内存中。当设置为FILE(1)则存放于文件中。temp_store_directorypragma可用于指定存放该文件的目录。注意当改变temp_store设置,所有已存在的临时表,索引、触发器及视图将被立即删除。

经测试,在类BBS应用上,通过以上调整,效率可以提高2倍以上。

总结于:
http://blog.chinaunix.net/uid-8447633-id-3321394.html
https://blog.csdn.net/kfqcome/article/details/6570495
https://blog.csdn.net/huanggang982/article/details/98167786
https://www.cnblogs.com/ludashi/p/4786830.html

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: C和SQLite是两种完全不同的技术。C是一种通用的编程语言,而SQLite是一种嵌入式数据库引擎。 C语言是一种功能强大的编程语言,广泛用于开发各种应用程序。它提供了丰富的库和函数,使得开发人员能够灵活地控制计算机的底层资源。通过C语言,我们可以进行低级别的内存操作、文件操作、网络编程等。 SQLite是一种嵌入式数据库引擎,可以嵌入到应用程序中,提供数据库功能。它是一种轻量级的关系型数据库系统,具有快速、可靠、易于使用等特点。SQLite使用简单的SQL语句来管理和操作数据,可以方便地进行数据查询、插入、更新和删除操作。由于其小巧、高效的特性,它被广泛地应用于各种移动设备、嵌入式系统和桌面应用程序中。 Excel是一个常用的电子表格软件,用于处理和分析数据。它提供了丰富的功能,如数据计算、图表绘制、数据筛选和排序等。通过Excel,我们可以方便地进行数据的录入、整理和分析,对大量的数据进行统计和可视化展示。 虽然C和SQLite、Excel都与数据处理有关,但它们之间的关联性不大。C语言可以用于开发与数据库或电子表格软件相关的应用程序,在应用程序层面上与SQLite和Excel进行交互。例如,可以使用C语言编写程序从SQLite数据库读取数据并在Excel中进行分析和展示。但是,C语言本身并不包含与SQLite或Excel的具体操作有关的功能。要实现与SQLite或Excel的具体操作,我们需要使用特定的库或API来处理。 ### 回答2: C sqlite和Excel都是广泛使用的数据管理工具。 首先,C语言是一种广泛使用的编程语言,可以用于开发各种应用程序。C语言提供了SQLite库,这是一个轻量级的关系型数据库管理系统。SQLite使用单一的磁盘文件来存储整个数据库,不需要独立的服务器进程,因此非常适合在嵌入式设备或简单应用程序中使用。C语言与SQLite可实现高效的数据存储、查询、更新和删除。 另一方面,Excel是一种电子表格软件,主要用于数据分析和管理。它提供了一种直观的界面,用户可以通过单元格输入数据、进行公式计算和数据整理。Excel可以用于记录和分析大量数据,包括数值、文本、日期和图表等。它还提供了诸如筛选、排序、函数和宏等功能,使得对数据进行复杂的操作和分析变得更加简便。 相较而言,C sqlite和Excel具有许多不同之处。C sqlite是一种编程工具,可以通过编写代码来实现对数据库的操作,而Excel则提供了一个图形化界面,无需编程即可进行数据处理和操作。C sqlite更适用于开发复杂的应用程序,而Excel更适合进行简单且快速的数据分析和管理。 总而言之,C sqlite和Excel都是为了帮助用户管理和处理数据而设计的工具。选择使用哪种工具应根据具体需求和要求来决定,是否需要进行编程,以及对数据处理的复杂度有何要求。 ### 回答3: c是一种编程语言,sqlite则是一种轻量级的嵌入式数据库管理系统,而excel是一种常用的电子表格软件。三者在数据库操作和数据存储方面有一些不同之处。 c作为一种编程语言,可以通过调用sqliteAPI来实现与sqlite数据库的连接和操作。通过编写c程序,我们可以创建、读取、更新和删除sqlite数据库中的数据。同时,c也提供了一些库函数来处理excel文件,可以实现对excel文件的读写和操作。 sqlite是一种嵌入式数据库管理系统,与传统的客户端-服务器模式的数据库系统不同,它将数据库嵌入到应用程序中,不需要额外的服务器进程。使用sqlite,我们可以在本地存储和管理数据,非常适用于移动设备或桌面应用。在c程序中,我们可以使用sqliteAPI来执行各种数据库操作,如创建表、插入数据、查询数据等。 excel是一种常用的电子表格软件,广泛应用于办公和数据分析领域。它提供了丰富的功能来处理和分析数据,如数据排序、筛选、图表制作等。通过c程序,我们可以使用一些库函数来读取和写入excel文件,实现对excel数据的读写和处理。 综上所述,c可以通过sqliteAPI来实现与sqlite数据库的连接和操作,并且还提供了一些库函数来处理excel文件。这使得我们能够在c程序中完成数据库操作和excel数据的读写和处理,为数据管理和处理提供了便利。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值