[在此处输入文章标题]
目录
三、windows命令行操作sqlite3数据库步骤... 5
四、VS同一exe工程中使用(sqlite数据库)源代码... 7
2、添加cpp文件并增加main函数和引用必要的头文件... 8
3、同一工程中使用sqlite3.c和sqlite3.h. 9
五、VS 不同工程中使用(sqlite.dll)自编译源工程动态库... 11
7、获取sqlite.lib和sqlite.dll文件... 14
六、VS不同工程中使用(sqlite.lib)自编译源工程静态库... 16
一、SQLite介绍
SQLite 是一个 开源C 语言进程内库,它实现了一个 小型小型、 快速、 自包含、 高可靠性、 全功能的 SQL 数据库引擎。与大多数其他 SQL 数据库不同,SQLite 没有单独的服务器进程。SQLite 是世界上使用最广泛的数据库引擎。SQLite 内置于所有手机和大多数计算机中,并捆绑在人们每天使用的无数其他应用程序中。
SQLite文件格式稳定、跨平台且向后兼容,开发人员承诺在2050 年保持这种状态。SQLite 数据库文件通常用作在系统之间传输丰富内容的容 以及数据的长期归档格式 。有超过 1 万亿 (1e12) 个 SQLite 数据库在活跃使用 。
SQLite源代码 属于公共领域,任何人都可以免费使用它以用于任何目的。
注意:中文字符的处理
sqlite3 SQL语句字符串输入,路径,Db文件的表字段等包含字符和字符串时,都是用UTF-8编码形式。也就是说,调用其功能且指定的字符串中含有中文时,如果编译器字符编码使用的是unicode等方式,需要手动转换为UTF-8格式。
二、使用SQLite的原因:对比磁盘文件操作
1.速度更快
它比磁盘文件操作的读写速度快35%,特别是对于碎片化,不连续的关系型数据。
2.占用系统资源更少
单个db文件一般在10K以下,且可以存储多个表。
3.原子操作文件稳定
系统崩溃、突然断电时,文件不易丢失。在使用fopen进行磁盘读写时,突然断电或关机或造成文件损坏,这是很大的弊病。
4.无限触发器
数据不是孤岛,利用此机能,在改变某个数据时可以触发其他数据的改变等动作。
使用fopen进行类似数据关联的话,编程量大大增加。
5.零配置
OS中无需安装其他驱动软件,就可以对本地DB文件进行管理。
6.多平台多语言库支持
开箱即用地支持 Android、*BSD、iOS、Linux、Mac、Solaris、VxWorks 和 Windows(Win32、WinCE、WinRT),丰富的接口,C++、C#、Objective-C、Java、Tcl、Perl、Python、Ruby、Erlang、JavaScript。利于日后物联网扩展。
7.多进程并发使
支持多个进程/线程同时访问(但不要类比互联网级别的C/S架构,它的优势还是
只在于有限多个进程同时访问)。将会自动安排访问的先后顺序,程序员只用关心业务逻辑,无须编程控制进程访问顺序。
8、支持SQL语言管理
三、windows命令行操作sqlite3数据库步骤
1、步骤1下载sqlite3数据库系统
官方文档:https://www.sqlite.org/index.html
安装包下载路径:https://www.sqlite.org/download.html
我是下载下面两个包
下载后解压,将exe、dll文件放到到某个路径(看自己习惯),这里我创建并放在了C:\sqlite文件夹。
2、新增环境变量
在控制面板中按照如下步骤操作。
3、在命令行中使用sqlite3命令操作数据库
需要知识:SQL语言编程基础、cmd常用命令
命令行操作:
4、使用第三方工具验证
辅助软件 SQLiteStudio或SQLiteExepert等。使用软件,打开路径下的文件,查看数据表中的详细数据以及表头、约束、触发器(这些见后面详解)等信息。
使用命令行能做的事比较少(关键是命令行我也不熟),上面的命令行操作只是演示作用。下面都是以在VS工程中使用.c源码为主。
四、VS同一exe工程中使用(sqlite数据库)源代码
(这同样适用于其他的开源项目)
1、创建空白工程
2、添加cpp文件并增加main函数和引用必要的头文件
3、同一工程中使用sqlite3.c和sqlite3.h
4、在exe工程中调用sqlite3功能
(这将在后面详述)。
五、VS 不同工程中使用(sqlite.dll)自编译源工程动态库
(这同样适用于其他的开源项目)
这种方式是最节约时间的,但是很明显,在大型项目中,它会让整个项目结构混乱。因为数据库管理可能只是整个工程的其中一项任务。什么都放在exe工程目录下,不是一个明智的选择。
1、将sqlite3工程创建为dll库
创建两个空白工程,其中一个为主exe,另一个为dll库。
2、将官网下载的源码放入sqlite3工程中
3、将sqlite3工程的类型改为dll
4、建立map文件这是生成lib文件的基础
5、建立def文件以确定需要引出为dll的内容
6、编辑def文件
7、获取sqlite.lib和sqlite.dll文件
这两个文件都会在VS设置的输出目录中找到,我这里使用的是Debug模式。利用dependency等工具可以查看这两个文件中的内容是否符合需要。
8、显示引用动态库
在exe工程合适的位置引用.h和.lib文件。这样,编译器在编译时即可根据.lib中指示的
路径和内容找到dll文件,并在exe运行需要时调用dll。
当然,这是显示引用的办法,你也可以用隐式引用。这需要在工程属性中增加设置.h和.dll的包含路径,这里不谈,不清楚的请网络搜索。
六、VS不同工程中使用(sqlite.lib)自编译源工程静态库
(同样适用于其他开源工程)
这种方式是直接将下载的源工程一行也不改,编译封装为独立的整体--静态库。使用时直接调库就完了。优点是节约时间且层次分明。因为从网站上下载的.h和.c内容过大,使用def导出dll库的方式需要手动更改def文件,有些耗时。
但使用静态库的缺点也很明显,这会大大增加调库者编译文件的尺寸和编译所需要的时间。
1、创建两个空白工程
一个为exe工程,另一个为lib工程
2、将需要生成lib库的工程设置属性
3、将sqlite3的源码添加进lib工程
4、在需要使用lib的其他工程中添加定义
5、直接在另外工程中使用lib功能
七、sqlite API使用详解
1、int sqlite3_config()
1)说明
参数1:配置选项。后续参数因参数1不同而不同。
这里使用的是SQLITE_CONFIG_LOG。这个选项用于配置sqlite全局错误日志。此时sqlite3_config后面有两个参数:
参数2:void(*)(void*,int,const char*) 函数指针。回调函数,它的参数1是用户数据,第二个参数是错误代码,由sqlite3_log()传递来;第三个参数是报警内容字符串,由sqlite3_log()传递来,这个字符串已经过sqlite3_snprintf()格式化,为UTF-8格式。
参数3:用户数据
当sqlite3_config(SQLITE_CONFIG_LOG,,)后面有函数指针时,每次sqlite发生错误,系统即会调用sqlite3_log(),然后sqlite3_log(),sqlite会在在错误发生时就内部开辟内存空间存储错误信息(代码和字符串内容),然后由sqlite3_log()函数传递给函数指针指定的回调函数。你可以在指定的回调函数中做显示,记录等操作。但原始信息是sqlite内部管理的(没此错误来了就new新的内存空间。新的错误来了,旧的就delete了)。如果sqlite3_config(SQLITE_CONFIG_LOG,,)后面是NULL,则什么也不会发生。
2)官网API手册截图
参考说明:API说明文档来自sqlite官网
3)工程代码示例
2、int sqlite3_open()
1)说明
参数1:包含路径的文件全称
参数2:返回句柄,被操作的db文件
打开数据库文件,这个函数没什么好说的。常用两中形式,sqlite3_open()和 sqlite3_open16()。参数一一个含义。只是当参数一指定的是相对路径时,有所区别。sqlite3_open()里面接受的是Unicode标准的UTF-8方案格式(编译器设置的“多字符集”;std库中的string内核;c语言的原始char*)。
如果绝对路径或相对路径不是当前路径时,且路径中间含有中文,你将不得不使用宽字符格式(编译器设置的Unicode标准的UTF-16方案格式;std库中的wstring内核;C语言的wchar_t*)和sqlite3_open16()
我使用的VS使用的unicode字符集(对比多字符集标准)时, UTF-16是默认的编码方式。代码如果指定为了char*、string。它将采用窄字节多字符集;指定了L,CString,wstring它将采用默认编码方式UTF-16。
2)官网说明
3)代码示例
3、int sqlite3_exec()
1)说明
参数1:db指针对象 sqlite3*
参数2:一条或多条UTF-8字符编码格式的SQL语言语句const char*
参数3:回调函数指针int (*callback)(void*,int,char**,char**)
参数4:用户数据void*
参数5:错误消息char **
sqlite3_exec()是sqlite3_prepare_v2(), sqlite3_step(), 和sqlite3_finalize()一系列函数的统一包装形式,它允许用户程序带入不同的多行SQL语句去执行不同的任务,而不必使用不同的C语言函数实现同样的效果。sqlite3_exec()可以一次执行多条UTF-8编码格式的SQL语句(应用程序中多条SQL语句使用同一条字符串),只需中间使用分号隔开。例如
rc = sqlite3_exec(db,"CREATE TABLE emploer(id int PRIMARY KEY,name varchar(20),addr varchar(30),sala real,sex varchar(2))",NULL,NULL,NULL);
rc = sqlite3_exec(db,"CREATE TABLE emploer(id int PRIMARY KEY,name varchar(20),addr varchar(30),sala real,sex varchar(2)); INSERT INTO emploer(id,name,addr,sala,sex) VALUES(1,'张三','huangshi',3000,'male')",NULL,NULL,NULL);
上面只运行一条SQL指令只是创建了表,下面运行了两条SQL指令,不仅创建了表,还插入了一条数据。如果参数三的函数指针非空,SQL语句执行结果每有一行就会调用一次回调函数。(一般不这么用,sqlite并不保证SQL语句的执行顺序,你无法在回调函数中获知这行到底执行的是指定几个操作中的哪个操作)
如果错误发生,不仅当前的SQL语句将不会执行,后面的语句也会跳出。如果sqlite3_exec的参数5非空,sqlite3_malloc()函数将会开辟内存,保存错误信息,并将指针传递给参数5。所以,记住编程时及时调用sqlite3_free()释放次内存。如果参数5非空,当无错误发生,参数5指针会在sqlite3_malloc()返回前被操作指向NULL,所以,编程时注意释放内存的条件(当然,sqlite3_free函数源码中也做了判定,不会出现未定义行为现象)。
如果参数4,回调函数返回值非零(换句话说,不是返回SQLITE_OK),则sqlite3_exec()将会立即返回SQLITE_ABORT,SQL语句执行被打断,回调函数也不会再次被当前的sqlite3_exec()调取。转而执行后面的语句。
回调函数的第二个参数int是SQL执行结果,数据表格的列数,第三个参数是 sqlite3_column_text()获取到的字符串指针的数组。也就是返回一个指针,这个指针指向一个指针数组,这个数组中每个元素都是一个字符串指针。每个字符串就是每次回调函数获取的这一行的第0到n列的数据打印成字符串的形式。回调函数的参数4就是以参数3同样形式返回的表头,也就是列名称,是从sqlite3_column_name()获取的。
2)官网说明
3)代码示例
4、in sqlite_get_table()
1)说明
参数1:db指针sqlite3 *db
参数2:SQL语句
参数3:输出参数,char***型,字符串指针数组的地址
参数4:输出参数,int*型,int型数据存储符合条件的行数
参数5:输出参数,int*型,int型数据存储符合条件的列数
参数6:错误消息。
这里面参数3546是有名堂的。调用者必须为参数4和参数5分配int型的空间。因为sqlite源代码中只是操作int*指针,并未开辟空间保存int型数据-行计数、列计数。
但是参数3,只需要调用者分配一个char**的指针空间。因为它的执行原理是sqlite3_get_table查询数据库表格,将符合条件的表格数据,包括表头按逐行逐列的顺序,将每项数据以字符串的形式一一拷贝到单独开辟的内存空间内(字符串间的空间并不连续),然后将每个字符串的地址组成字符串数组,将这这个字符串数组的地址返还到调用者,然后sqlite3_get_table就不管了,调用者需要手动释放由sqlite3_get_table开辟的内存空间。
参数6是另外一套管理模式。这个是报警内容字符串,它同样由sqlite动态开辟内存空间。为啥不需要手动释放呢?因为sqlite会在下次错误发生时,自动释放旧的,并为新的报警内容开辟新的内存空间。所以并不需要用户释放内存空间。
这个一个函数,源码使用了3种方式管理内存空间。这些也是比较常见的内存空间管理方式。很多系统原生API和开源库都会使用。
另外需要注意的就是参数3和参数4,参数3,char***型。它指向的内存空间char**是一个一维数组,元素是char*字符串。那首元素是啥呢?是表头中第一列,也就是数据表第一列的列名称。然后按照上面说的顺序逐行逐列将字符串指针存入数组。所以,符合条件的数据的条数是参数4,但char**字符串指针数组中的元素个数有(参数4+1)*参数5个。多出来的一行是表头。
2)官网说明
3)代码示例
Sqlite与其他数据库一样,使用SQL语言可以实现触发器,用户定义数据,约束,索引等功能,不在本文讨论范围。需要的自己研读官网手册。