我在客户端开发时由于需要使用数据库,于是选择了轻巧的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);