SQLite3-轻量级数据库

        SQLite主页:SQLite Home Page

        SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月。 至2021年已经接近有21个年头,SQLite也迎来了一个版本 SQLite3 已经发布。下面介绍 SQLite3 的使用方法。


目录

一、文件准备

二、编译静态库

1. 编译文件

2. 编译过程

3. 拓展-当只有dll文件时

4. 文件使用说明

三、编译动态库

1. 编译文件

2. 编译环境配置

3、文件使用说明

四、SQLite3常用函数

1. 创建/打开数据库 (sqlite3_open)

2. 非回调使用sql语句查询数据库 (sqlite3_get_table)

3. 回调执行sql语句 (sqlite3_exec)

4. 回调函数 (callback)

5. 调试数据库 (*sqlite3_errmsg)

6. 关闭数据库 (sqlite3_close)

7. 释放错误信息 (sqlite3_free)   

8. 释放查询结果 (sqlite3_free_table)

五、程序示例

六、数据库管理工具介绍

1. 免费且保持更新

2. 免费但可能已停止更新

3. 收费版-通常功能丰富且更新及时


一、文件准备

        以下文件均从SQLite官网下载。

  • sqlite-amalgamation-3380000.zip

  • sqlite-dll-win64-x64-3380000.zip

 

二、编译静态库

        本节介绍文件 sqlite3.lib 的编译方法。

1. 编译文件

  • 模块定义文件:sqlite3.def    

2. 编译过程

        开始 --> Visual Studio 2022 --> x64 Native Tools Command Prompt for VS 2022

  • 打开 sqlite3.def 文件的路径
cd /d D:\tmp-source\qt-hmi\SQL\sqlite-dll-win64-x64-3330000
  • 生成 sqlite3.lib 文件
LIB /DEF:sqlite3.def /machine:X64 //64位
LIB /DEF:sqlite3.def /machine:X86 //32位

3. 拓展-当只有dll文件时

  • 需要先通过 dll 文件生成 def 文件
dumpbin /exports sqlite3.dll > sqlite3.def
LIB /DEF:sqlite3.def /machine:X64 //64位
LIB /DEF:sqlite3.def /machine:X86 //32位
// OR
LIB /DEF:sqlite3.def /machine:i386 /out:sqlite3.lib

4. 文件使用说明

        包含 sqlite3.h 头文件,将 sqlite3.lib 库文件链接到项目中即可。

#pragma comment (lib,"sqlite3.lib") 

三、编译动态库

        本节介绍编译 sqlite.dll 的方法以及编译环境的配置。

1. 编译文件

  • 头文件:sqlite3.h
                   
    sqlite3ext.h
  • 源文件:sqlite3.c        
  • 模块定义文件:sqlite3.def       

2. 编译环境配置

        此处仅展示32位dll文件编译环境配置

  • 创建 win32 项目,设置 常规 --> 配置类型 和 高级(VS2022) --> 目标文件拓展名 为 .dll
  • C/C++ --> 预处理器 --> 预处理器定义 (添加) 
SQLITE3_EXPORTS
SQLITE_ENABLE_RTREE                
SQLITE_ENABLE_COLUMN_METADATA
SQLITE_ENABLE_FTS5
  • C/C++ --> 不使用预编译头
  • 链接器 --> 输入 --> 附加库依赖项 (添加) sqlite3.lib 文件
  • 链接器 --> 输入 --> 模块定义文件 (添加) sqlite3.def 文件

3、文件使用说明

        将编译完成的动态库和可执行程序放置同一目录下。

四、SQLite3常用函数

1. 创建/打开数据库 (sqlite3_open)

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

功能:创建/打开数据库。
参数:szFilename:数据库路径及名称;
           ppDb:数据库句柄。
返回值:执行成功返回 SQLITE_OK (值为0),否则返回其他值。

2. 非回调使用sql语句查询数据库 (sqlite3_get_table)

int sqlite3_get_table(
      sqlite3 *pDb,         /* An open database */
      const char *szSql,    /* 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 */
    );

功能:非回调执行sql语句。
参数:pDb:数据库句柄;
           szSql:要执行的SQL语句;
           pazResult:查询结果 (一维数组);
           pnRow:查出结果数据条数 (查询结果行数);
           pnColumn:查出结果包含的字段数 (查询结果列数);
           pzErrMsg:程序报错时输出的错误信息。
返回值:执行成功返回 SQLITE_OK,否则返回其他值。
备注:pazResult的字段值是连续的一维数组,索引区间 [0,pnColumn-1] 内存储字段名称,从索引 pnColumn 开始,后面都存字段内容。

3. 回调执行sql语句 (sqlite3_exec)

int sqlite3_exec(
      sqlite3 *pDb,/* The database on which the SQL executes */
      const char *szSql,/* The SQL to be executed */
      sqlite3_callback xCallback,/* Invoke this callback routine */
      void *pArg,/* First argument to xCallback() */
      char **pzErrMsg             /* Write error messages here */
      );

功能:执行零个或多个SQL 语句 (增删查改),查询的结果返回给回调函数 xCallback。
参数:pDb:数据库句柄;
           szSql:待执行的SQL 语句字符串,以’\0’结尾;
           xCallback:回调函数,用来处理查询结果,如果不需要回调 (比如做insert 或者delete 操作时),可以输入NULL;
           pArg:要传入回调函数的指针参数,没有可以置为NULL;
           paErrMsg:返回错误信息,注意是指针的指针。
返回值:执行成功返回 SQLITE_OK,否则返回其他值。

4. 回调函数 (callback)

 typedef int (*sqlite3_callback)(
                void *para, 
                int nColCount, 
                char **pazResult,                char **pazColName
                );

功能:由用户处理查询的结果。
参数:para:从sqlite3_exec() 传入的参数指针;
           nColCount:查询到的这一条记录有多少个字段(即这条记录有多少列);
           pazResult:查询出来的数据都保存在这里 (char* 的一 维数组,以‘\0’结尾);
           pazResultName:与 pazResult 对应,表示对应数据的字段名称。
返回值:执行成功返回 SQLITE_OK,否则返回其他值。

5. 调试数据库 (*sqlite3_errmsg)

const char *sqlite3_errmsg(sqlite3 *pDB);


功能:获取最近调用的 API 返回的错误信息 (错误信息以 UTF-8 编码返回,并在下一次调用任何SQLite API 时被自动清除)。
输入参数:pDB:打开的数据库句柄。
返回值:错误信息字符串的指针。

6. 关闭数据库 (sqlite3_close)

int sqlite3_close(sqlite3 *pDb);

功能:关闭数据库。
参数:pDb:数据库句柄。
返回值:执行成果返回 SQLITE_OK,若句柄繁忙返回 SQLITE_BUSY。

7. 释放错误信息 (sqlite3_free)   

void sqlite3_free(void *pErrMsg );

功能:释放存放错误信息的内存空间。
参数:pErrMsg: 返回的错误信息。  

8. 释放查询结果 (sqlite3_free_table)

void sqlite3_free_table(char ***pazResult);

参数:pazResult:查询结果 (一维数组)。

五、程序示例

        下面的程序中展示了前文所述方法的具体用法。

// Win32ConsoleApp.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
using namespace std;

bool bCallbackFlag = true;
// 回调函数
static int callback(void* NotUsed,int nColCount,char** pazResult,char** pazResultName)
{

	if (bCallbackFlag == true)
	{
		for (int nIndex = 0; nIndex < nColCount; ++nIndex)
		{
			printf("%s\t",pazResultName[nIndex] ? pazResultName[nIndex] : "NULL");
		}
		printf("\n");
		printf("-----------------------\n");
		bCallbackFlag = false;
	}
	for (int nIndex = 0; nIndex < nColCount; ++nIndex)
	{
		printf("%s\t",pazResult[nIndex] ? pazResult[nIndex] : "NULL");
	}
	printf("\n");
	return 0;
}

int _tmain(int argc,_TCHAR* argv[])
{
	typedef struct cPerson
	{
		char* name;
		int age;
		char* sex;
	} cPerson;

	cPerson OfficePerson[] = {
		"David",22,"man","Eve",28,"Frand",21,"woman"
	};

	sqlite3 *pDb; // 数据库句柄
	char *szErrMsg; // 错误信息

	// 打开数据库连接   
	long nRet = sqlite3_open("people.db",&pDb);
	assert(SQLITE_OK == nRet);

	// 使用sqlite3_exec()创建表  
	const char *szSql = "CREATE TABLE IF NOT EXISTS person(name VARCHAR(128),"
		"age INTEGER,"
		"sex VARCHAR(7)"
		");";
	nRet = sqlite3_exec(pDb,szSql,NULL,&szErrMsg);
	if (nRet != SQLITE_OK)
	{
		printf("%s\n",szErrMsg);
		sqlite3_close(pDb);
		return 1;
	}

	// 使用sqlite3_exec()删除字段
	szSql = "DELETE  FROM person;";
	nRet = sqlite3_exec(pDb,szErrMsg);
		sqlite3_close(pDb);
		return 1;
	}

	// 使用sqlite3_exec()插入数据  
	szSql = "INSERT INTO person(name,age,sex) VALUES(\"Alice\",15,\"woman\");";
	nRet = sqlite3_exec(pDb,&szErrMsg);
	assert(SQLITE_OK == nRet);

	szSql = "INSERT INTO person(name,sex) VALUES(\"Bob\",18,\"man\");";
	nRet = sqlite3_exec(pDb,sex) VALUES(\"Charli\",11,&szErrMsg);
	assert(SQLITE_OK == nRet);

	// 使用sqlite3_exec()查询数据  
	printf("===== query by sqlite3_exec() =====\n\n");
	szSql = "SELECT name,sex FROM person;";
	nRet = sqlite3_exec(pDb,callback,&szErrMsg);
	assert(SQLITE_OK == nRet);

	// 使用sqlite3_get_table()查询数据  
	printf("\n\n===== query by sqlite3_get_table() =====\n\n");
	szSql = "SELECT name,sex FROM person;";
	int nRow,nCol;
	char **pazResult;
	nRet = sqlite3_get_table(pDb,&pazResult,&nRow,&nCol,&szErrMsg);
	assert(SQLITE_OK == nRet);
	for (int nIndex = 0; nIndex < nCol; ++nIndex)
	{
		printf("%s\t",pazResult[nIndex] ? pazResult[nIndex] : "NULL");
	}
	printf("\n");
	printf("-----------------------\n");
	for (int nIndex = nCol; nIndex < (nRow+1)*nCol; ++nIndex)
	{
		printf("%s\t",pazResult[nIndex] ? pazResult[nIndex] : "NULL");
		if ((nIndex+1)%nCol == 0)
		{
			printf("\n");
		}
	}
	

	
	// 使用sqlite3_prepare_v2(),sqlite3_bind_...() 插入数据
	const char* pzTail;
	sqlite3_stmt* pstmt;
	szSql = "INSERT INTO person(name,sex) VALUES(?,?,?);";
	nRet = sqlite3_prepare_v2(pDb,strlen(szSql),&pstmt,&pzTail);
	assert(SQLITE_OK == nRet);
	for (int nIndex = 0; nIndex < sizeof(OfficePerson) / sizeof(cPerson); ++nIndex)
	{
		int nCol = 1;
		sqlite3_bind_text(pstmt,nCol++,OfficePerson[nIndex].name,strlen(OfficePerson[nIndex].name),NULL);
		sqlite3_bind_int(pstmt,OfficePerson[nIndex].age);
		sqlite3_bind_text(pstmt,OfficePerson[nIndex].sex,strlen(OfficePerson[nIndex].sex),NULL);

		sqlite3_step(pstmt);
		sqlite3_reset(pstmt);
	}
	sqlite3_finalize(pstmt);

	// 使用sqlite3_prepare_v2(),sqlite3_column_...() 查询数据
	printf("\n\n====== query by sqlite3_prepare_v2() ======\n\n");
	const unsigned char* pTmp;
	int age;
	szSql = "SELECT name,sex FROM person;";
	nRet = sqlite3_prepare_v2(pDb,&pzTail);
	assert(SQLITE_OK == nRet);
	bool nPrintFlag = true;
	while (true)
	{
		if (nPrintFlag == true)
		{
			printf("name\tage\tsex\n");
			printf("-----------------------\n");
			nPrintFlag = false;
		}
		nRet = sqlite3_step(pstmt);
		if (SQLITE_DONE == nRet)
		{
			sqlite3_finalize(pstmt);
			break;
		}
		if (SQLITE_ROW == nRet)
		{
			int nCol = 0;
			pTmp = sqlite3_column_text(pstmt,nCol++);
			printf("%s\t",pTmp);
			age = sqlite3_column_int(pstmt,nCol++);
			printf("%d\t",age);
			pTmp = sqlite3_column_text(pstmt,nCol++);
			printf("%s\n",pTmp);
			continue;
		}

		printf("something error.\n");
		sqlite3_finalize(pstmt);
		break;
	}

	sqlite3_close(pDb); // 关闭数据库

	return 0;
}

六、数据库管理工具介绍

        本节内容源自博客园某位博主,进行简单排版。原文链接如下:SQLite可视化管理工具汇总 - Man_华 - 博客园 (cnblogs.com)

1. 免费且保持更新

        截至 2012/9/14 最新版本 SQLiteSpy 1.9.1 – 28 Jul 2011
        单文件,界面设计紧凑,较稳定,功能较少,创建表与添加数据均需sql语句,快捷键教方便,
作为数据浏览和修改工具极佳,视图编码为utf-8,对gbk2312显示乱码。能满足一般的应用,但没有导出数据表功能,同时只能打开一个数据库文件,不支持二进制字段编辑。

        【推荐】开源,单文件;
        更新及时,功能完善的sqlite2和sqlite3工具,视图编码支持utf8。支持导出数据格式:csv、html、plain、sql、xml。可同时打开多个数据库文件,支持查看和编辑二进制字段。

        个人免费 ,需安装;
        功能非常强大,如果上述两款不能满足,就试试这个吧。

        基本功能齐全,可以将数据表导出为sql数据格式。

2. 免费但可能已停止更新

        两年未更新,截至2012/9/14最新版本 V3.04 04/12/2010;但xp下只是别gbk2312编码,界面紧凑,功能全面。

        简单易用,具有基本数据库管理查询功能,并且能够导入和导出数据表,支持sql文件和csv两种方式。似乎不再更新,截至2012/9/14最新版本:Version 2.0b1 released - Based on Qt4.6 - 12/09/2009。

        功能齐全,界面有多语言,带导出功能,很久未更新,只识别sqlite2,可用于sqlite2到sqlite3的转换,win xp下视图的编码为gbk2312,对utf-8显示乱码。截至2012/9/14最新版本 [0.8.3.2]大概是2007年10月份。

3. 收费版-通常功能丰富且更新及时

        有中文版。

        非商业单用户,该公司出品了很多数据库管理工具,如同类产品 SQLite Maestro。

        需安装。

        很好用,很强大,不过价格较高,适合企业使用。

相关文章

SQLite架构简单,又有Json计算能力,有时会承担Json文件/RES...
使用Python操作内置数据库SQLite以及MySQL数据库。
破解微信数据库密码,用python导出微信聊天记录
(Unity)SQLite 是一个软件库,实现了自给自足的、无服务器...
安卓开发,利用SQLite实现登陆注册功能