• 基于C API的SQLite3基本数据库操作


    SQLite是一款开源嵌入式文件型数据库,这个主要是和其他一些C/S架构的关系型数据库比较而来的,比如MySQL等。

    说他是嵌入式,因为SQLite的所有功能全部包装在一个dll中,我们只需要使用其中的导出接口就可以操作SQLite数据库,这样使得数据存储功能能够很方便的集成进用户的程序中,并运行在客户程序的进程空间中

    说他是文件型,因为SQLite的数据库文件就是一个独立文件(SQLite本身不限制数据库文件的扩展名),再没有其他的了,数据,表结构,查询,视图等等都保存在这个数据库文件中,不会依赖任何数据库环境

    SQLite的主要特点:
    1。无需部署,0配置,无服务端
    2。跨平台
    2。数据文件管理方便
    3。较完善的SQL92标准支持,SQLite基本实现了SQL92标准,其他的一些不兼容的地方,可以参看官方相关说明,链接:
    http://www.sqlite.org/omitted.html
    4。SQL语句执行速度快,具体的对比数据,网上的评测有很多,这里就不多说了
    5。应用较广。最著名的集成应该数Android了吧,其他的PHP ,Python等都做了集成,所以还是很不错的
    6。完美的Unicode编码支持。SQLite的接口中,凡是涉及字符串的都是用UTF8或UTF16编码交互,有的同时提供这两种编码的接口函数,所以多语种支持绝对不是问题(这也是我偏爱SQLite的很重要的原因,呵呵)。

    好了,下面说说基于C API的SQLite操作,这里谢绝讨论其他的一些包装库,这不是本文的范围,当然SQLite的接口包装库函数还是很多的,基本覆盖各种主流开发语言。如基于Object Pascal的sqlitesimpledelphi,想了解这个库的朋友可以查看我的其他博文:
    Delphi 2010下使用sqlitesimpledelphi连接SQLite数据库及中文乱码问题的解决
    http://hi.baidu.com/2356/blog/item/4a5549366d94afd6a3cc2bc7.html
    sqlitesimpledelphi修正以支持Unicode,Delphi 2010 测试通过
    http://hi.baidu.com/2356/blog/item/236ceb2455f2520c4c088db2.html

    SQLite的数据库操作其实和常规的数据库操作流程是一样的:
    1。连接数据库。
    2。构造SQL语句并执行
    3。对于SELECT语句,可以获取查询结果
    4。数据库使用完毕之后,关闭数据库

    这里说明一下,下面所介绍的函数不会涵盖所有的API函数,毕竟SQLite针对同一个功能点提供了不同的API函数,主要表现在参数和配置功能上,有需要深入了解的朋友可以参考官方的文档。

    1。打开数据库
    API函数:
    int sqlite3_open(
    const char *filename,   /* 数据库文件路径(UTF-8编码) */
    sqlite3 **ppDb          /* 输出: SQLite 数据库句柄 */
    );
    int sqlite3_open16(
    const void *filename,   /* 数据库文件路径(UTF-16) */
    sqlite3 **ppDb          /* 输出: SQLite 数据库句柄 */
    );
    如果调用成功会返回SQLITE_OK,否则返回错误码。

    2。构造SQL语句,这里就不多说了,这和SQLite本身无关,可以根据需要使用适当的方法构造即可,注意传给SQLite函数的时候,字符串编码要记得转换为UTF8/UTF16

    3。执行SQL语句。
    在SQLite中执行SQL语句比较简单的方法是调用函数:
    int sqlite3_exec(
    sqlite3*,                                  /* 打开的数据库句柄 */
    const char *sql,                           /* UTF8编码的SQL语句 */
    int (*callback)(void*,int,char**,char**), /* 回调函数,对于SELECT语句返回的结果处理在回调函数中进行 */
    void *,                                    /* 传递给回调函数的参数 */
    char **errmsg                              /* 相关错误信息 */
    );

    其实sqlite3_exec只是封装了sqlite3_prepare、sqite3_step(即SQL中的预编译技术)的,主要目的是为使用者提供方便,笔者个人觉得使用后者会更加好一点,这里先做一下总结:

    int sqlite3_prepare(
    sqlite3 *db,            /* 打开的数据库句柄 */
    const char *zSql,       /* UTF8编码的SQL语句,可以参数化 */
    int nByte,              /* SQL语句的字节长度,可以传递-1,即字符串以\0结尾 */
    sqlite3_stmt **ppStmt, /* 输出:预编译之后的SQL语句句柄 */
    const char **pzTail     /* 输出: 指向zSql缓冲区中跳过有效SQL字符串的第一个字节 */
    );

    int sqlite3_prepare_v2(
    sqlite3 *db,            /* 打开的数据库句柄 */
    const char *zSql,       /* UTF8编码的SQL语句,可以参数化 */
    int nByte,              /* SQL语句的字节长度,可以传递-1,即字符串以宽字符\0结尾 */
    sqlite3_stmt **ppStmt, /* 输出: 预编译之后的SQL语句句柄 */
    const char **pzTail     /* 输出: 指向zSql缓冲区中跳过有效SQL字符串的第一个字节 */
    );

    int sqlite3_prepare16(
    sqlite3 *db,            /* 打开的数据库句柄 */
    const void *zSql,       /* UTF16编码的SQL语句,可以参数化 */
    int nByte,              /* SQL语句的字节长度,可以传递-1,即字符串以宽字符\0结尾 */
    sqlite3_stmt **ppStmt, /* 输出: 预编译之后的SQL语句句柄 */
    const void **pzTail     /* 输出: 指向zSql缓冲区中跳过有效SQL字符串的第一个字节 */
    );

    int sqlite3_prepare16_v2(
    sqlite3 *db,            /* 打开的数据库句柄 */
    const void *zSql,       /* UTF16编码的SQL语句,可以参数化 */
    int nByte,              /* SQL语句的字节长度,可以传递-1,即字符串以宽字符\0结尾 */
    sqlite3_stmt **ppStmt, /* 输出: 预编译之后的SQL语句句柄 */
    const void **pzTail     /* 输出: 指向zSql缓冲区中跳过有效SQL字符串的第一个字节 */
    );

    其中带参数的SQL语句可以这样定义参数:

    ?NNN 
    :VVV 
    @VVV 
    $VVV 
    参数编号从1开始,例如:INSERT into db values(?1, ?2)

    v2版本函数时SQLite根据需要添加的增强函数,新的程序推荐使用v2版本函数,只需与原来函数的区别,可以参考官方原文

    int sqlite3_step(sqlite3_stmt*);
    执行一次预编译SQL语句,在这之前,如果SQL是参数化的,可以调用sqlite3_bind来绑定数据,int、string、blob等等
    如果执行成功会返回SQLITE_DONE,如果查询有结果会返回SQLITE_ROW,并可以通过API获取结果中的第一行数据,需要获取下一行数据可以再次调用sqlite3_step直到返回SQLITE_DONE表示后面没有数据了
    如果需要重新对预编译的SQL绑定数据并执行,需要先reset一下,然后再调用step,即函数:
    int sqlite3_reset(sqlite3_stmt *pStmt);

    下面是绑定数据到预编译SQL语句的相关函数:
    以下函数的第一个参数指代预编译的SQL句柄,第二个参数指代绑定的参数编号,对应于参数化的SQL语句中的参数编号:

    int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
    该函数用于绑定二进制数据BLOB,其中最后一个参数是一个回调函数,当成功绑定数据后,会被调用,一般用于自动释放对应的缓冲区

    int sqlite3_bind_double(sqlite3_stmt*, int, double);
    该函数绑定double浮点数

    int sqlite3_bind_int(sqlite3_stmt*, int, int);
    该函数绑定int整数

    int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    该函数用于绑定具有64位长度的整数,对应于C中的long long结构,由于一个int的范围可能无法满足超大数据量的要求,所以SQLite也支持64位整数,毕竟SQLite官方声称SQLite是支持最大2T的数据的

    int sqlite3_bind_null(sqlite3_stmt*, int);
    该函数绑定一个空数据到指定列

    int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
    该函数绑定一段字符串,源字符串是UTF8编码的

    int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
    该函数绑定一段字符串,源字符串是UTF16编码的

    int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
    该函数绑定以SQLite结构sqlite3_value存储的通用数据,其中sqlite3_value可以是上述的所有类型,此函数不太常用

    int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
    该函数绑定指定大小的全零BLOB数据

    3。获取SQL查询结果
    对于SELECT语句,还需要能够获取结果。上面也提到调用sqlite3_step之后,对于有结果的查询会返回第一行结果,这时可以通过API函数获取当前行的指定字段结果:

    const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
    该函数以BLOB数据格式获取对应列的数据,BOLB长度使用sqlite3_column_bytes获取

    int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
    int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
    该函数可以用于返回BLOB和字符串的字节长度。对于BLOB,两个函数效果是一样的,但是对于字符串sqlite3_column_bytes返回的是UTF8编码的字符串长度,而sqlite3_column_bytes16返回的是UTF16编码的字符串长度,其间会做必要的字符串格式转换

    double sqlite3_column_double(sqlite3_stmt*, int iCol);
    该函数返回double数据列

    int sqlite3_column_int(sqlite3_stmt*, int iCol);
    该函数返回int数据列

    sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
    该函数返回64位整数,即long long数据

    const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
    const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
    该函数返回字符串,其中sqlite3_column_text输出的字符串使用UTF8编码

    sqlite3_column_text16使用UTF16编码
    int sqlite3_column_type(sqlite3_stmt*, int iCol);
    该函数返回对应列的数据类型

    sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
    该函数以sqlite3_value结构体返回数据

    上面是根据列ID来获取对应的列数据的,如果想通过列名称获取列数据,则需要将列名称转换为对应的列ID,可以使用下面的函数:
    const char *sqlite3_column_name(sqlite3_stmt*, int N);
    const void *sqlite3_column_name16(sqlite3_stmt*, int N);
    该函数返回对应列的名称

    4。关闭数据库

    int sqlite3_close(sqlite3 * db);
    使用该函数可以关闭数据库

    好了,基本的调用流程就这么些了,看完这篇文章,应该能够完成基本的数据读写操作了,至于其他的高级操作,有兴趣的朋友可以登录SQLite官方网站查看,这里就不在本文多说了。

  • 相关阅读:
    逆向初级-win32(四)
    逆向初级-C++(三)
    逆向初级-C语言(二)
    逆向初级-汇编(一)
    Kimabll数仓架构下如何确定模型落地哪些表
    浅谈数据仓库设计
    (转)Go语言的%d,%p,%v等占位符的使用
    (转)深入MySQL源码 学习方法 何登成专家
    (转)浅析MySQL二段锁
    (转)MySQL:为什么无法KILL在processlist中的语句
  • 原文地址:https://www.cnblogs.com/hnrainll/p/2170492.html
Copyright © 2020-2023  润新知