C中sqlite3你知多少

laokugonggao
发布于 2020-9-3 18:08
浏览
0收藏

开发客户端时,我需要使用数据库,因此我选择了一个轻量级的sqlite数据库进行研究,今天,我将与您分享我总结的SQLite使用文档。

源码下载

wget http://www.sqlite.org/2017/sqlite-autoconf-3160200.tar.gz
tar xvzf sqlite-autoconf-3160200.tar.gz

交叉编译
 

./configure --host=arm-himix200-linux --prefix=/home/zjucad/wangzhiqiang/toolDir/sqlite-autoconf-3160200/libs
make
make install

按顺序执行上述命令后sqlite的链接库和头文件等就会出现在prefix目录下

api使用
基本的使用流程


sqlite3_open()->sqlite3_prepare_v2()->sqlite3_step()->sqlite3_column()->sqlite3_finalize()->sqlite3_close()

 

具体介绍:

 

int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
打开一个数据库,第一个参数为数据库的路径,注意这里不能为:memory:,这表示存在内存中,第二个参数为返回,返回这个数据库的handle,函数返回值是int,成功则返回SQLITE_OK,失败的话可以通过sqlite3_errmsg()查看错误信息。
注:sqlite还有个sqlite3_open_v2()函数,添加一些flag,看着不太常用。
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 */
);
准备数据库语句的上下文,相当于编译sql语句,最后由step函数执行编译好的语句,ppStmt需要自己首先定义好,最后一个参数基本传NULL。
注:sqlite还有个sqlite3_prepare()函数,但是现在官方推荐使用v2版本,有错误v2版本能够立即暴露出来。

一般使用sqlite3_prepare_v2()都是和sqlite3_bind_xxx()系列函数一起使用,例如执行插入语句,使用sqlite3_bind_xxx()可以动态绑定某些参数的值,后续给出示例代码。

 
int sqlite3_step(sqlite3_stmt*);
执行数据库语句

 


int sqlite3_reset(sqlite3_stmt *pStmt);
重置数据库上下文,当需要重新bind参数时可以使用这个函数,避免多次prepare。

 


int sqlite3_finalize(sqlite3_stmt *pStmt);
删除数据库语句的上下文,调用了sqlite3_prepare_v2()后无论成功失败都需要调用,避免内存泄漏。

 


int sqlite3_close(sqlite3 *);
关闭数据库

 

在执行查询操作时,可能结果不止一条,那sqlite3_step()函数就会返回SQLITE_ROW直到所有结果都被查询到会返回SQLITE_DONE,这里每次sqlite3_step()返回SQLITE_ROW后都需要再次调用返回下一次查询的结果。

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_column_type()获取某一列的类型,通过sqlite3_column_count()函数获取这次查询结果共有多少列。

在一些简单的场景下也可以使用sqlite3的wrapper函数

主要有sqlite3_exec()和sqlite3_get_table()函数,相当于调用了sqlite3_prepare_v2()->sqlite3_step()->sqlite3_finalize()这个流程。

 

区别是sqlite3_exec()在查询中需要添加回调函数,sqlite3_get_table()主要用在查询上,没有回调,会把查询到的结果存到一块地址。

 

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

注意这里的最后一个参数是错误信息,如果执行函数没有返回SQLITE_OK,可以查看errmsg处的信息,这块内存也需要自己手动调用sqlite3_free()来释放。
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);

sqlite3_get_table()主要用在查询上,会把查询到的结果存到一块地址。由调用者手动调用sqlite3_free_table()释放内存。

注意事项
sqlite3-column-text()等函数返回的地址不需要自己free,sqlite会在调用sqlite3_step() or sqlite3_reset() or sqlite3_finalize()时自动释放

如何设置自增字段
 字段是integer 的primary key就会自增

CREATE TABLE t1(
a INTEGER PRIMARY KEY,
b INTEGER
);

如上代码,字段a就会自增,最大值是9223372036854775807,如果insert超过了这个数量,就会返回SQLITE_FULL错误,但90%的数据库行数可能不会超过这个数量。

示例代码

sqlite3 *db_;
std::string sql =
        "create table if not exists sqlite("
        "id INTEGER primary key     AUTOINCREMENT,"
        "value      int64      not null);";
char *err_msg = NULL;
int ret = sqlite3_exec(db_, sql.c_str(), NULL, 0, &err_msg);
if (ret != SQLITE_OK) {
    std::cout << "create table error " << err_msg;
    sqlite3_free(err_msg);
    return false;
}
std::string sql =
        "insert into sqlite(value) values(?1)";
sqlite3_stmt *stmt;
int ret = sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, NULL);
if (ret != SQLITE_OK) {
    std::cout << "prepare sql error " << ret << " " << sqlite3_errcode(db_);
    return false;
}
if (sqlite3_bind_int64(stmt, 1, 1) != SQLITE_OK) {
    std::cout << "bind timestamp error " << sqlite3_errcode(db_);
    return false;
}
if (sqlite3_step(stmt) != SQLITE_DONE) {
    std::cout << "step insert fail " << sqlite3_errcode(db_);
    return false;
}
sqlite3_finalize(stmt);

有问题,欢迎私信或留言

已于2021-3-23 11:52:04修改
收藏
回复
举报
回复