sqlite使用样例与utf编码

62 篇文章 0 订阅
13 篇文章 0 订阅

个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

提起sqlite,可谓是大名鼎鼎,作为一个单机文件数据库,一个易用的关系数据库,使用起来确实很方便。
另外sqlite存储采用的B+树结构,该结构会为表数据做页面汇聚,查询效率是非常高的。

关于如何来使用sqlite,总结了一些简单的使用样例。
数据库使用样例中,有打开数据库,创建表,插入数据,查询数据,这几种DDL与DML操作。
另外由于sqlite的接口限制约束,要求字符串使用utf编码格式,所以也会涉及编码使用的部分知识。
注:样例运行环境在linux下,缺省的LANG编码设置为zh_CN.UTF8

打开数据库

关注两种方式,一种是使用sqlite3_open打开数据,一种是使用sqlite3_open16打开数据库;
其中sqlite3_open比较适合在linux下使用,在linux缺省编码格式是utf8,适合接口参数需要,filename采用char类型的utf8字符串。
其中sqlite3_open16比较适合在windows下使用,适合打开可能带中文路径的数据库,filename采用char16_t
类型的utf16字符串。
原因见接口使用说明中:

The encoding used for the filename argument of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever codepage is currently defined.
Filenames containing international characters must be converted to UTF-8 prior to passing them into sqlite3_open() or sqlite3_open_v2().

函数说明:

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

使用sqlite3_open的样例:

#include "sqlite3.h"
#include "stdio.h"
#include "string.h"
int main(int argc, char** argv)
{
  int rc = SQLITE_OK;
  sqlite3* db;
  const char* dbname = "./mydb.db";
  rc = sqlite3_open(dbname, &db);
  if (rc != SQLITE_OK){
    printf("open db<%s> failed<%s>\n", dbname, sqlite3_errmsg(db));
    sqlite3_close(db);
    return -1; 
  }
  printf("open db<%s> succ!\n", dbname);

  sqlite3_close(db);
  return 0; 
}

使用sqlite3_open16的样例:

#include "sqlite3.h"
#include "stdio.h"
#include <string>
#include <locale>
#include <codecvt>
int main(int argc, char** argv)
{
  int rc = SQLITE_OK;
  sqlite3* db;
  std::u16string str = u"./mydb.db";
  std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> myconv;
  std::string utf8str = myconv.to_bytes(str);
  const char* dbname = utf8str.c_str(); 
  rc = sqlite3_open16(str.c_str(), &db);
  if (rc != SQLITE_OK){
    printf("open db<%s> failed<%s>\n", dbname, sqlite3_errmsg(db));
    sqlite3_close(db);
    return -1; 
  }
  printf("open db<%s> succ!\n", dbname);
  sqlite3_close(db);
  return 0; 
}

创建表

创建表使用sqlite3_exec执行建表语句
函数说明

// The sqlite3_exec() interface is a convenience wrapper around [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
// that allows an application to run multiple statements of SQL without having to use a lot of C code. 
//  The sqlite3_exec() interface runs zero or more UTF-8 encoded, 
// semicolon-separate SQL statements passed into its 2nd argument, 
// in the context of the [database connection] passed in as its 1st argument.
SQLITE_API 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 */
);

创建表的语句如下:

  // create table
  const char* sqlstr = "create table if not exists testtbl(id integer(4), name TEXT, other integer(4))";
  char* errmsg;
  rc = sqlite3_exec(db, sqlstr, 0, 0, &errmsg);  
  if (rc != SQLITE_OK){
    printf("execute create table failed<%s>\n", errmsg);
    sqlite3_free(errmsg);
    return -1;
  }
  printf("create table succ!\n");

插入数据

插入数据一般使用sqlite3_stmt结构准备数据,然后使用sqlite3_step提交数据,使用sqlite3_finalize清理stmt数据;
准备数据过程中,首先使用sqlite3_prepare创建绑定stmt,使用sqlite3_bind_int/text绑定数据。
// The life-cycle of a prepared statement object usually goes like this:
// 1. Create the prepared statement object using [sqlite3_prepare_v2()].
// 2. Bind values to [parameters] using the sqlite3_bind_*() interfaces.
// 3. Run the SQL by calling [sqlite3_step()] one or more times.
// 4. Reset the prepared statement using [sqlite3_reset()] then go back to step 2. Do this zero or more times.
// 5. Destroy the object using [sqlite3_finalize()].
当然了,插入数据也可以像在工具中一样,拼装insert sql语句,使用sqlite3_exec方式直接执行提交插入数据。
使用stmt方式提交数据时,接口中也会区分出utf8方式和utf16方式,utf8是缺省方式。
注意事项:
需要注意一点,无论使用utf8接口,还是utf16接口,对于sqlite来说,数据都是按照utf8存储的;
对于utf16而言,接口中内部做了向utf8的转换,内部也是最终走的utf8接口写入数据。

函数说明:

// The use of the UTF-8 interfaces is preferred, as SQLite currently does all parsing using UTF-8.  
// The UTF-16 interfaces are providedas a convenience.  
// The UTF-16 interfaces work by converting the input text into UTF-8, then invoking the corresponding UTF-8 interface.
// parameters:
// The second argument, "zSql", is the statement to be compiled, encoded as either UTF-8 or UTF-16.  
// The sqlite3_prepare(), sqlite3_prepare_v2(), and sqlite3_prepare_v3() interfaces use UTF-8, 
// and sqlite3_prepare16(), sqlite3_prepare16_v2(), and sqlite3_prepare16_v3() use UTF-16.
// The use of the new "vX" interface is recommended for new applications but the legacy interface will continue to be supported.
SQLITE_API 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 */
);
SQLITE_API 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 */
);
SQLITE_API int sqlite3_prepare16_v2(
  sqlite3 *db,            /* Database handle */
  const void *zSql,       /* SQL statement, UTF-16 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const void **pzTail     /* OUT: Pointer to unused portion of zSql */
);
SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, void(*)(void*));
SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void(*)(void*), unsigned char encoding);
SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*));
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
// In the legacy interface, the return value will be either [SQLITE_BUSY], [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE].
// With the "v2" interface, any of the other [result codes] or [extended result codes] might be returned as well.
// [SQLITE_BUSY] means that the database engine was unable to acquire the database locks it needs to do its job.
// [SQLITE_DONE] means that the statement has finished executing successfully.
// If the SQL statement being executed returns any data, then [SQLITE_ROW] is returned each time a new row of data is ready for processing by the caller.
// [SQLITE_ERROR] means that a run-time error (such as a constraint violation) has occurred. 
// [SQLITE_MISUSE] means that the this routine was called inappropriately.
SQLITE_API int sqlite3_step(sqlite3_stmt*);
// The sqlite3_finalize() function is called to delete a [prepared statement].
SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);

插入数据的语句如下:

  // insert data
  sqlite3_stmt *stmt;
  rc = sqlite3_prepare_v2(db, "insert into testtbl values(?1, ?2, ?3)", -1, &stmt, NULL);
  if (rc != SQLITE_OK){
     printf("prepare failed<%s>\n", sqlite3_errmsg(db)); 
    sqlite3_close(db);
     return -1;
  }
  const char *msg ="hello";
  sqlite3_bind_int(stmt, 1, 1);
  sqlite3_bind_text(stmt, 2, msg, strlen(msg), NULL);
  sqlite3_bind_int(stmt, 3, 2);
  rc = sqlite3_step(stmt);
  if (rc == SQLITE_ERROR){ //SQLITE_DONE, SQLITE_OK
    printf("execute write failed<%s>\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return -1;
  }
  sqlite3_finalize(stmt);  
  printf("write data succ!\n");

查询数据

查询数据和插入数据有类似的地方:
插入数据是通过接口准备数据-绑定插入的数据;
查询数据是通过接口获取数据-绑定查询到的数据;
都会使用stmt这个结构,使用的方式有一些差异
使用到的函数有sqlite3_prepare准备sql语句,使用sqlite3_step执行查询出一条语句,使用sqlite3_column_*读取字段,然后使用sqlite3_step尝试读取下一条数据。
注意事项:
我们已经知道了,对于sqlite来说,内部数据都是按照utf8存储的;对于utf16接口而言,接口中内部做了与utf8的转换;
所以呢,如果我们写查询语句时,无论按照utf8接口,还是utf16接口,内部都是按照utf8查询匹配数据的。
同样的,对于读取出来的数据,当我们使用sqlite3_column_text16方式时,得到的结果也是通过查询到的utf8数据,转码为utf16得到的。

使用到的函数:

SQLITE_API 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 */
);
SQLITE_API int sqlite3_step(sqlite3_stmt*);
SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);

查询样例:

  const char* querymsg = "select * from testtbl where 1=1";
  sqlite3_stmt *querystmt;
  rc = sqlite3_prepare_v2(db, querymsg, -1, &querystmt, NULL);
  if (rc != SQLITE_OK){
    printf("query failed<%s>\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return -1;
  }
  do{
    rc = sqlite3_step(querystmt);
    if (rc != SQLITE_ROW){
      break;
    }
    int id = sqlite3_column_int(querystmt, 0);
    const unsigned char* name = sqlite3_column_text(querystmt, 1);
    int other = sqlite3_column_int(querystmt, 2);
    printf("record: %d|%s|%d|\n", id, name, other);
  }while(rc != SQLITE_DONE);
  sqlite3_finalize(querystmt);  
  printf("query data succ!\n");

That’s all~~~

个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春夜喜雨

稀罕你的喜欢!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值