




已阅读5页,还剩35页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Sqlite入门手册目录Sqlite简介3一、简介:3Sqlite环境配置61. 下载 SQLite3 源码:62. 下载 SQLite3.dll:73. 生成 SQLite3.lib 文件:84. 生成或下载 SQLite3 Shell 文件:105. 创建数据库以及数据表:126.mspdb80.dll无法找到15Sqlite操作入门16一、创建数据表:16二、表的修改:18三、表的删除:19四、创建视图:19Sqlite的锁机制20事务20SQLite中的锁20保留状态(reserved)22待定状态(pending)23独占状态(exclusive)23Sqlite实例代码241.常规数据插入242.高效的批量数据插入:263.数据查询30SQLite C/C+ 接口简介341.0 Core Objects And Interfaces341.1 Typical Usage Of Core Routines And Objects372.0 Convenience Wrappers Around Core Routines383.0 Binding Parameters and Reusing Prepared Statements384.0 Extending SQLite395.0 Other Interfaces40Sqlite的其他信息41Sqlite简介一、简介:SQLite是目前最流行的开源嵌入式数据库,和很多其他嵌入式存储引擎相比(NoSQL),如BerkeleyDB、MemBASE等,SQLite可以很好的支持关系型数据库所具备的一些基本特征,如标准SQL语法、事务、数据表和索引等。事实上,尽管SQLite拥有诸多关系型数据库的基本特征,然而由于应用场景的不同,它们之间并没有更多的可比性。下面我们将列举一下SQLite的主要特征: 1). 管理简单,甚至可以认为无需管理。 2). 操作方便,SQLite生成的数据库文件可以在各个平台无缝移植。 3). 可以非常方便的以多种形式嵌入到其他应用程序中,如静态库、动态库等。 4). 易于维护。 综上所述,SQLite的主要优势在于灵巧、快速和可靠性高。SQLite的设计者们为了达到这一目标,在功能上作出了很多关键性的取舍,与此同时,也失去了一些对RDBMS关键性功能的支持,如高并发、细粒度访问控制(如行级锁)、丰富的内置函数、存储过程和复杂的SQL语句等。正是因为这些功能的牺牲才换来了简单,而简单又换来了高效性和高可靠性。 二、SQLite的主要优点 1. 一致性的文件格式: 在SQLite的官方文档中是这样解释的,我们不要将SQLite与Oracle或PostgreSQL去比较,而是应该将它看做fopen和fwrite。与我们自定义格式的数据文件相比,SQLite不仅提供了很好的移植性,如大端小端、32/64位等平台相关问题,而且还提供了数据访问的高效性,如基于某些信息建立索引,从而提高访问或排序该类数据的性能,SQLite提供的事务功能,也是在操作普通文件时无法有效保证的。 2. 在嵌入式或移动设备上的应用: 由于SQLite在运行时占用的资源较少,而且无需任何管理开销,因此对于PDA、智能手机等移动设备来说,SQLite的优势毋庸置疑。 3. 内部数据库: 在有些应用场景中,我们需要为插入到数据库服务器中的数据进行数据过滤或数据清理,以保证最终插入到数据库服务器中的数据有效性。有的时候,数据是否有效,不能通过单一一条记录来进行判断,而是需要和之前一小段时间的历史数据进行特殊的计算,再通过计算的结果判断当前的数据是否合法。在这种应用中,我们可以用SQLite缓冲这部分历史数据。还有一种简单的场景也适用于SQLite,即统计数据的预计算。比如我们正在运行数据实时采集的服务程序,我们可能需要将每10秒的数据汇总后,形成每小时的统计数据,该统计数据可以极大的减少用户查询时的数据量,从而大幅提高前端程序的查询效率。在这种应用中,我们可以将1小时内的采集数据均缓存在SQLite中,在达到整点时,计算缓存数据后清空该数据。 4. 数据分析: 可以充分利用SQLite提供SQL特征,完成简单的数据统计分析的功能。这一点是CSV文件无法比拟的。 5. 产品Demo和测试: 在需要给客户进行Demo时,可以使用SQLite作为我们的后台数据库,和其他关系型数据库相比,使用SQLite减少了大量的系统部署时间。对于产品的功能性测试而言,SQLite也可以起到相同的作用。 三、和RDBMS相比SQLite的一些劣势: 1. C/S应用: 如果你有多个客户端需要同时访问数据库中的数据,特别是他们之间的数据操作是需要通过网络传输来完成的。在这种情况下,不应该选择SQLite。由于SQLite的数据管理机制更多的依赖于OS的文件系统,因此在这种操作下其效率较低。 2. 数据量较大: 受限于操作系统的文件系统,在处理大数据量时,其效率较低。对于超大数据量的存储,甚至不能提供支持。 3. 高并发: 由于SQLite仅仅提供了粒度很粗的数据锁,如读写锁,因此在每次加锁操作中都会有大量的数据被锁住,即使仅有极小部分的数据会被访问。换句话说,我们可以认为SQLite只是提供了表级锁,没有提供行级锁。在这种同步机制下,并发性能很难高效。四、个性化特征: 1. 零配置: SQLite本身并不需要任何初始化配置文件,也没有安装和卸载的过程。当然也不存在服务器实例的启动和停止。在使用的过程中,也无需创建用户和划分权限。在系统出现灾难时,如电源问题、主机问题等,对于SQLite而言,不需要做任何操作。 2. 没有独立的服务器: 和其他关系型数据库不同的是,SQLite没有单独的服务器进程,以供客户端程序访问并提供相关的服务。SQLite作为一种嵌入式数据库,其运行环境与主程序位于同一进程空间,因此它们之间的通信完全是进程内通信,而相比于进程间通信,其效率更高。然而需要特别指出的是,该种结构在实际运行时确实存在保护性较差的问题,比如此时,应用程序出现问题导致进程崩溃,由于SQLite与其所依赖的进程位于同一进程空间,那么此时SQLite也将随之退出。但是对于独立的服务器进程,则不会有此问题,它们将在密闭性更好的环境下完成它们的工作。 3. 单一磁盘文件: SQLite的数据库被存放在文件系统的单一磁盘文件内,只要有权限便可随意访问和拷贝,这样带来的主要好处是便于携带和共享。其他的数据库引擎,基本都会将数据库存放在一个磁盘目录下,然后由该目录下的一组文件构成该数据库的数据文件。尽管我们可以直接访问这些文件,但是我们的程序却无法操作它们,只有数据库实例进程才可以做到。这样的好处是带来了更高的安全性和更好的性能,但是也付出了安装和维护复杂的代价。 4. 平台无关性: 这一点在前面已经解释过了。和SQLite相比,很多数据库引擎在备份数据时不能通过该方式直接备份,只能通过数据库系统提供的各种dump和restore工具,将数据库中的数据先导出到本地文件中,之后在load到目标数据库中。这种方式存在显而易见的效率问题,首先需要导出到另外一个文件,如果数据量较大,导出的过程将会比较耗时。然而这只是该操作的一小部分,因为数据导入往往需要更多的时间。数据在导入时需要很多的验证过程,在存储时,也并非简简单单的顺序存储,而是需要按照一定的数据结构、算法和策略存放在不同的文件位置。因此和直接拷贝数据库文件相比,其性能是非常拙劣的。 5. 弱类型: 和大多数支持静态类型的数据库不同的是,SQLite中的数据类型被视为数值的一个属性。因此对于一个数据表列而言,即便在声明该表时给出了该列的类型,我们在插入数据时仍然可以插入任意类型,比如Integer的列被存入字符串hello。针对该特征唯一的例外是整型的主键列,对于此种情况,我们只能在该列中存储整型数据。 6. SQL语句编译成虚拟机代码: 很多数据库产品会将SQL语句解析成复杂的,相互嵌套的数据结构,之后再交予执行器遍历该数据结构完成指定的操作。相比于此,SQLite会将SQL语句先编译成字节码,之后再交由其自带的虚拟机去执行。该方式提供了更好的性能和更出色的调试能力。Sqlite环境配置1. 下载 SQLite3 源码:虽然说摆弄 c/c+ 有很长时间了,但是说到用 c/c+ 来摆弄数据库倒还真是没有弄过,一直有关数据库的项目似乎都用 .Net 给去 OK 了,就好比 SQLite,现在的项目就是用的 SQLite.Net,有什么东西都是用 c# 直接操作 SQLite.Net 了,而相对底层的东西则使用 c/c+ 完成且封装成 DLL 供 c# 调用就 OK 了。不过有的时候自己在写一些小东西的时候,可能也会有些数据需要本地存储的,以前为了图个简单,就直接存文件咯,不过要是相对隐私点的东西的话,我想还是有个数据库比较好,这不是就有 SQLite3 了嘛,注意一下哈,SQLite3 是供 c/c+ 代码来使用的,如果是 .Net 的话那就得用 SQLite.Net 了,废话少说,进入正题了,首先我们需要下载好 SQLite3 的相关文件,官网地址:/download.html我们先下载的是 SQLite3 的源码,下载好后,你可以解压缩出来,然后你就会看到 4 个 C/C+ 文件了。而我们每次在 C/C+ 中使用 SQLite3 时总是需要其中的头文件 sqlite3.h2. 下载 SQLite3.dll:然后需要下载的是 SQLite3 的 DLL 文件以及导出库,下载完后你可以解压出来,你会发现只有 SQLite3.dll 和 SQLite3.def 两个文件,3. 生成 SQLite3.lib 文件:做过 c/c+ DLL 的都知道,.def 文件可以用来定义一个 DLL 中 API 的导出,所以我们可以打开 SQLite3.def 看看,里面定义的 API 名称就是 SQLite3.dll 所导出的 API,而在 C/C+ 中如果你要链接到其他的 DLL 上,你必须要有那个 DLL 的导出库,也就是 .lib 文件,而我们这里没有导出文件(Lib)怎么办呢?没有那就根据 DLL 和.def 文件来生成一个 .lib 文件不就 OK 了 。首先将 SQLite3.dll 和 SQLite3.def 文件拷贝到 VS 安装目录下的 Bin 文件夹,比如我安装的是 VS2010,且默认安装在 C:Program Files 目录下面,那么你就需要将上面的两个文件拷贝到以下目录:C:Program FilesMicrosoft Visual Studio 10.0VCbin然后打开 Visual Studio 命令提示符,且定位到上面的这个目录,然后输入命令:lib /def:sqlite3.def /machine:ix86,然后你就会在 Bin 目录下发现已经生成了 SQLite3.lib 文件。4. 生成或下载 SQLite3 Shell 文件:关于这 SQLite3 的 Shell 文件呢,就是用来创建 SQLite3 数据库啊,创建表啊之类的东西,说白了就是个 SQLite Admin 的控制台界面,当然咯,控制台这个东西并不怎么好用,所以你可以考虑换个其他的带 GUI 的工具来管理你的 SQLite3 数据库。有个工具不错,叫 DataBase.Net,什么乱七八糟的数据库它都可以连接上去,不过要 .Net Framework 的支持。对于这个 SQLite3 的 Shell 文件你可以直接在 SQLite 的官方网站上下载到,而后,除了下载 SQLite3 的 Shell 工具外,我们还可以自己编译 SQLite 源代码来生成这个工具,前面我们已经下载好了 SQLite3 的源代码,并且源代码里面还有一个叫做 shell.c 的文件,其实这个文件就可以用来处理 SQLite3 Shell 命令的,所以我们可以直接在 VS2010 下新建一个 Console 项目,然后将源代码里面的 4 个 CC+ 文件拷贝到项目中,然后直接编译,你也可以得到 SQLite3 的 Shell 工具 SQLite3.exe。5. 创建数据库以及数据表:这里使用麻烦点的方式,即使用 SQLite3 的 Shell 工具,下面的例子呢就是很简单的方式,即使用 SQLite3 的 Shell 工具来创建个 DataBase,然后再创建个 Table,再插入几条记录,查询一下就 OK 了。具体命令就看下面的截图就好了:首先在命令行下定位到你的 SQLite3.exe 也就是 Shell 程序所在的目录:比如我的 SQLite3.exe 所在目录为:E:CodeSQLitesqlite-shell-win32-x86-3071000然后输入命令 sqlite3 testDB.db 从而创建 SQLite 数据库,然后输入命令 create table testDB_ID(ID int, Number int) 来创建数据表 testDB_ID然后输入命令 ; 从而执行上面的创建表的命令。执行完这些命令后,在你的 Shell 程序也就是 SQLite3.exe 所在的位置中发现你创建的 testDB.db 数据库了。其实上面的这种创建数据库的方式太麻烦了,还不如直接用 Database.Net 来做,方便很多,比如我用 DataBase.Net 打开我们上面创建的这个 testDB.db 数据库,用这个工具来管理数据库很方便。6.mspdb80.dll无法找到在cmd中键入cl执行编译时会出现mspdb80.dll无法找到的情况,是因为VCBin下没有“msobj80.dll,mspdb80.dll,mspdbcore.dll,mspdbsrv.exe”这四个文件,解决的方法:1 直接从Common7IDE下复制这四个文件到VCBin下即可解决2 添加系统变量(Path),这样:我的电脑-属性-高级-环境变量-系统变量,在path中添加C:Program FilesMicrosoft Visual Studio 8Common7IDE;,注意结尾最后用“;”隔开!这样在用cl编译就不会出现mspdb80.dll文件找不到的错误了。Sqlite操作入门一、 创建数据表:该命令的语法规则和使用方式与大多数关系型数据库基本相同,因此我们还是以示例的方式来演示SQLite中创建表的各种规则。但是对于一些SQLite特有的规则,我们会给予额外的说明。注:以下所有示例均是在sqlite自带命令行工具中完成的。 1). 最简单的数据表: sqliteCREATE TABLEtesttable (first_col integer); 这里需要说明的是,对于自定义数据表表名,如testtable,不能以sqlite_开头,因为以该前缀定义的表名都用于sqlite内部。 2). 创建带有缺省值的数据表: sqliteCREATE TABLEtesttable (first_col integerDEFAULT0, second_col varcharDEFAULThello); 3). 在指定数据库创建表: sqliteATTACH DATABASEd:/mydb.dbASmydb; sqliteCREATE TABLEmydb.testtable (first_col integer); 这里先通过ATTACH DATABASE命令将一个已经存在的数据库文件attach到当前的连接中,之后再通过指定数据库名的方式在目标数据库中创建数据表,如mydb.testtable。关于该规则还需要给出一些额外的说明,如果我们在创建数据表时没有指定数据库名,那么将会在当前连接的main数据库中创建该表,在一个连接中只能有一个main数据库。如果需要创建临时表,就无需指定数据库名,见如下示例: -创建两个表,一个临时表和普通表。 sqliteCREATE TEMP TABLEtemptable(first_col integer); sqliteCREATE TABLEtesttable (first_col integer); -将当前连接中的缓存数据导出到本地文件,同时退出当前连接。 sqlite.backupd:/mydb.db sqlite.exit -重新建立sqlite的连接,并将刚刚导出的数据库作为主库重新导入。 sqlite.restored:/mydb.db -查看该数据库中的表信息,通过结果可以看出临时表并没有被持久化到数据库文件中。 sqlite.tables testtable 4). IF NOT EXISTS从句: 如果当前创建的数据表名已经存在,即与已经存在的表名、视图名和索引名冲突,那么本次创建操作将失败并报错。然而如果在创建表时加上IF NOT EXISTS从句,那么本次创建操作将不会有任何影响,即不会有错误抛出,除非当前的表名和某一索引名冲突。 sqliteCREATE TABLEtesttable (first_col integer); Error: table testtable already exists sqliteCREATE TABLE IF NOT EXISTStesttable (first_col integer); 5). CREATE TABLE . AS SELECT: 通过该方式创建的数据表将与SELECT查询返回的结果集具有相同的Schema信息,但是不包含缺省值和主键等约束信息。然而新创建的表将会包含结果集返回的所有数据。 sqliteCREATE TABLEtesttable2AS SELECT*FROMtesttable; sqlite.schematesttable2 CREATE TABLE testtable2(first_col INT); .schema命令是sqlite3命令行工具的内置命令,用于显示当前数据表的CREATE TABLE语句。 6). 主键约束: -直接在字段的定义上指定主键。 sqliteCREATE TABLEtesttable (first_col integerPRIMARY KEY ASC); -在所有字段已经定义完毕后,再定义表的数约束,这里定义的是基于first_col和second_col的联合主键。 sqliteCREATE TABLEtesttable2 ( . first_col integer, . second_col integer, . PRIMARY KEY(first_col,second_col) . ); 和其他关系型数据库一样,主键必须是唯一的。 7). 唯一性约束: -直接在字段的定义上指定唯一性约束。 sqliteCREATE TABLEtesttable (first_col integerUNIQUE); -在所有字段已经定义完毕后,在定义表的唯一性约束,这里定义的是基于两个列的唯一性约束。 sqliteCREATE TABLEtesttable2 ( . first_col integer, . second_col integer, .UNIQUE(first_col,second_col) . ); 在SQLite中,NULL值被视为和其他任何值都是不同的,这样包括和其他的NULL值,如下例: sqlite DELETE FROM testtable; sqlite SELECT count(*) FROM testtable; count(*) - 0 sqlite INSERT INTO testtable VALUES(NULL); sqlite INSERT INTO testtable VALUES(NULL); sqlite SELECT count(*) FROM testtable; count(*) - 2 由此可见,两次插入的NULL值均插入成功。 8). 为空(NOT NULL)约束: sqliteCREATE TABLEtesttable(first_col integerNOT NULL); sqlite INSERT INTO testtable VALUES(NULL); Error: testtable.first_col may not be NULL 从输出结果可以看出,first_col已经被定义了非空约束,因此不能在插入NULL值了。 9). 检查性约束: sqliteCREATE TABLEtesttable (first_col integerCHECK(first_col INSERT INTO testtable VALUES(4); sqlite INSERT INTO testtable VALUES(20);- 20违反了字段first_col的检查性约束(first_col CREATE TABLEtesttable2 ( . first_col integer, . second_col integer, .CHECK(first_col 0ANDsecond_col CREATE TABLE testtable (first_col integer); sqliteALTER TABLEtesttableRENAME TOtesttable2; sqlite.tables testtable2 通过.tables命令的输出可以看出,表testtable已经被修改为testtable2。 2). 新增字段: sqlite CREATE TABLE testtable (first_col integer); sqliteALTER TABLEtesttableADD COLUMNsecond_col integer; sqlite.schematesttable CREATE TABLE testtable (first_col integer, second_col integer); 通过.schema命令的输出可以看出,表testtable的定义中已经包含了新增字段。 关于ALTER TABLE最后需要说明的是,在SQLite中该命令的执行时间是不会受到当前表行数的影响,也就是说,修改有一千万行数据的表和修改只有一条数据的表所需的时间几乎是相等的。三、表的删除: 在SQLite中如果某个表被删除了,那么与之相关的索引和触发器也会被随之删除。在很多其他的关系型数据库中是不可以这样的,如果必须要删除相关对象,只能在删除表语句中加入WITH CASCADE从句。见如下示例: sqlite CREATE TABLE testtable (first_col integer); sqliteDROP TABLEtesttable; sqliteDROP TABLEtesttable; Error: no such table: testtable sqliteDROP TABLE IF EXISTStesttable; 从上面的示例中可以看出,如果删除的表不存在,SQLite将会报错并输出错误信息。如果希望在执行时不抛出异常,我们可以添加IF EXISTS从句,该从句的语义和CREATE TABLE中的完全相同。四、创建视图:我们这里只是给出简单的SQL命令示例,具体的含义和技术细节可以参照上面的创建数据表部分,如临时视图、IF NOT EXISTS从句等。 1). 最简单的视图: sqliteCREATE VIEWtestviewASSELECT * FROM testtable WHERE first_col 100; 2). 创建临时视图: sqliteCREATE TEMP VIEWtempviewASSELECT * FROM testtable WHERE first_col 100; 3). IF NOT EXISTS从句: sqliteCREATE VIEWtestviewASSELECT * FROM testtable WHERE first_col 100; Error: table testview already exists sqliteCREATE VIEW IF NOT EXISTStestviewASSELECT * FROM testtable WHERE first_col 100;五、删除视图: 该操作的语法和删除表基本相同,因此这里只是给出示例: sqliteDROP VIEWtestview; sqliteDROP VIEWtestview; Error: no such view: testview sqliteDROP VIEW IF EXISTStestview;Sqlite的锁机制在SQLite中,锁是一个重要而又基本的概念。与锁密切相关的一个基本概念是事务。首先,为了更好的理解锁的概念,我们简单回顾一下什么是事务?事务事务定义了一组SQL命令的边界,这组命令或者作为一个整体被全部执行,或者都不执行,这被称为数据库完整性的原子性原则,关于事务的典型例子就是银行转帐。事务由3个命令控制:begin、commit和rollback。begin之后和commit之前的所有操作都可以被取消。commit命令提交所执行的所有操作。与之类似,rollback还原begin之后的所有操作。那么在数据库中,事务和锁在查询处理中密切相关。查询总是在事务内执行,事务又涉及到锁,所以如果锁控制不当,会产生很多问题。接下来,让我们谈谈SQLite中的锁。SQLite中的锁SQLite采用粗粒度的锁。当一个连接要写数据库时,所有其他的连接被锁住,直到写连接结束它的事务。SQLite有一个加锁表,用来帮助不同的写数据库都能够在最后一刻再加锁,以保证最大的并发性。SQLite有5种不同的锁状态:未锁定(unlocked)、共享(shared)、保留(reserved)、待定(pending)和排它(exclusive)。每个数据库连接在同一时刻只能处于其中的一个状态(见下图),每种状态(未锁定(unlocked)状态除外)都有一种锁与之对应。图中所示,所有的事务都是从未锁定(unlocked)、保留(reserved)或排他锁开始的。默认情况下,一切都从未锁定(unlocked)开始。白色的锁状态-未锁定(unlocked)、待定(pending)、共享(shared)和保留(reserved),全部都可以在同一时间同一数据库的不同连接种存在。不过,从灰色的待定锁开始,限制就多了。灰色的待定状态代表锁正在被某个连接拥有,即某个想要获取独占锁的写操作。与此对应,白色的待定状态表示连接获取和释放共享锁的途径。尽管有这些不同的锁状态,但是所有的SQLite事务都可以归结为两种类型之一:读事务和写事务。这也是图种描绘的最终内容:读操作、写操作以及它们如何在一起工作。下面,我们就从读事务和写事务两个方面讨论。 读事务从select语句的锁进程开始,它的路径比较简单。执行select语句的连接启动事务,从未锁定转到共享锁,提交之后回到未锁定状态,操作结束。这里我们提出两个疑问:1. 执行两个语句会发生什么?2. 它们的锁路径是什么?这两个疑问取决于是否运行在自动提交模式下。考虑如下实例:123456db = open(worlds.db)db.exec(begin)db.exec(select * from sometables)db.exec(select * from sometables)db.exec(commit)db.close()这里有明确的begin命令开始,两个select命令在一个事务种执行,因此它们在同一个共享状态下执行。第一个exec()运行,让连接进入共享状态;然后第二个exec()运行;最后,手动提交命令,让连接从共享状态回到未锁定状态。代码的锁路径如下所示:UNLOCKED-PENDING-SHARED-UNLOCKED现在考虑没有begin和commit命令的情况。两个select命令运行在自动提交模式下。因此,它们各自经历完整的路径。现在,代码的锁路径如下所示:UNLOCKED-PENDING-SHARED-UNLOCKED-PENDING-SHARED-UNLOCKED由于该代码只是读取数据,因此,可能不会产生多大差异,但在自动提交模式下的确会两次锁定文件,而不是其他方式中那样只锁定一次。这样的做法,你可能会发现,可以在两个select exec()调用之间插入修改数据库的操作,因此,这样做无法确保两个命令返回相同的结果。相反,如果有mit命令,可以保证它们的结果完全相同。 写事务下面说说数据库写操作,例如update语句。首先,连接必须遵从与select相同的路径,先到共享状态。所有的操作-写操作或读操作-都必须经历;未知锁-待定锁-共享锁。保留状态(reserved)连接尝试向数据库写入内容时,必须从共享锁转换到保留锁。如果它获得保留锁,则准备好开始进行数据修改。即使连接真的不能在此时修改数据库,它也可以将修改内容存储在本地pager内的内存缓存中,也就是上一篇中提到的页面缓存。当连接进入保留状态时,pager初始化回滚日志。回滚日志是一个文件,用于回滚和故障恢复。具体地说,它拥有将数据库还原到事务开始之前的原来状体啊的数据库页。当B-tree修改页时,pager将这些数据库页都存放到日志文件。比如说,对于update修改的每条记录,页面获取与原始记录相关的数据库页,并将它们复制到日志中。日志就拥有事务开始之前的一些数据库内容。因此,要撤销事务时,pager只是简单地将日志文件中的内容复制回数据库中。这样,数据库就还原到事务开始前的状态。保留状态下,pager实际上管理三种页:已修改页、未修改页和日志页。已修改页是包含B-tree已改变记录的页,这些页存储在页缓存中。未修改页是B-tree读取但并未改变的页,它们是诸如select命令之类的结果。最后是日志页,它就是已修改页的原始版本。日志页不会存储在页面缓存中,但B-tree修改前会将其写入日志。因为页面缓存,写操作连接的确可以在保留状态完成实际的工作,而不用干扰其他(读操作)连接。因此,SQLite可以有效地让多个读操作和一个写操作同一时间在同一数据库中工作。唯一需要注意的是,写操作连接要将所做的修改存储在页面缓存中,而不是数据库文件中。此外要注意,给定数据库同一时间只能有一个保留或独占连接-但是多个读操作可以和一个写操作并存。待定状态(pending)当连接完成update操作,并提交事务时,pager开始进入独占状态的过程。一旦获得待定锁,并继续持有该锁,阻止其他连接获取待定锁。这里的待定锁也被称为网关锁,因为写操作继续持有待定锁,其他连接无法从未锁定转换到共享状态,结果是没有可以进入数据库的新连接:没有新的读操作,没有新的写操作。挂起状态实际上是损耗阶段。写操作保证它可以排队等待数据库-只要每个人都守规矩且行为得当,最终都可以获得独占锁。只有其他已有共享锁的连接可以继续正常工作。待定状态下,写操作等待这些连接完成并释放其共享锁。独占状态(exclusive)独占状态中,主要工作是将修改的页从页面缓存刷新到数据库文件。这时要慎重,因为pager开始实际修改数据库了。在pager开始写入修改的页前,首先要处理日志。它会检查日志的完整内容是否已写入磁盘。这种情况下,依然很可能,即使pager已将页写入日志文件,但是操作系统具有很多缓存,因此,可能还有一部分内容在操作系统的缓存中(也许不是全部)。将日志提交到磁盘非常重要,因为如果程序或系统在pager写入数据库文件时崩溃,日志是日后还原数据库文件的唯一方式。如果在系统崩溃前,日志页没有完整地写入磁盘,那么数据库就无法还原到其原来的状态,因为内存中的日志页在系统崩溃时丢失了。这种情况下,如果运气好的话,还有一个处于不一致状态的数据库,如果不走运的话,也许数据库也损坏了。一旦处理完日志,pager就可以将所有已修改的页复制到数据库文件。下一步做什么取决于事务模式。比如此处说的情况,事务自动提交,然后pager清理日志,清除页缓存,从独占锁回到未锁定状态。如果该事务未提交,pager继续持有独占锁,日志继续发挥作用,直到发出COMMIT或者ROLLBACK命令。至此,以读事务和写事务为两大方面,对锁的5种状态之间的转换以及所起到的作用,分别做了举例和总结。对于SQLite中5种锁的状态的转换,仅仅是需要了解的基本概念,相关的知识还有很多,比如自动提交模式下对于效率有什么影响?页面缓存的大小对于保留锁状态过渡到独占锁状态的影响?等等还有很多其他方面需要了解,这里只是做了基本介绍。Sqlite实例代码1. 常规数据插入1). 创建测试数据表。2). 通过INSERT语句插入测试数据。3). 删除测试表。#include #include #include using namespace std; void doTest() sqlite3* conn = NULL; /1. 打开数据库 int result = sqlite3_open(D:/mytest.db,&conn); if (result != SQLITE_OK) sqlite3_close(conn); return; const char* createTableSQL = CREATE TABLE TESTTABLE (int_col INT, float_col REAL, string_col TEXT); sqlite3_stmt* stmt = NULL; int len = strlen(createTableSQL); /2. 准备创建数据表,如果创建失败,需要用sqlite3_finalize释放sqlite3_stmt对象,以防止内存泄露。 if (sqlite3_prepare_v2(conn,createTableSQL,len,&stmt,NULL) != SQLITE_OK) if (stmt) sqlite3_finalize(stmt); sqlite3_close(conn); return; /3. 通过sqlite3_step命令执行创建表的语句。对于DDL和DML语句而言,sqlite3_step执行正确的返回值 /只有SQLITE_DONE,对于SELECT查询而言,如果有数据返回SQLITE_ROW,当到达结果集末尾时则返回 /SQLITE_DONE。 if (sqlite3_step(stmt) != SQLITE_DONE) sqlite3_finalize(stmt); sqlite3_close(conn); return; /4. 释放创建表语句对象的资源。 sqlite3_finalize(stmt); printf(Succeed to create test table now.n); int insertCount = 10; /5. 构建插入数据的sqlite3_stmt对象。 const char* insertSQL = INSERT INTO TESTTABLE VALUES(%d,%f,%s); const char* testString = this is a test.; char sql1024; sqlite3_stmt* stmt2
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 事故安全培训心德课件
- 支气管哮喘康复护理
- 护理临床总带教老师竞聘
- 项目总监年度个人工作总结
- 事业单位a类课件
- 教研员蹲点汇报
- 购房合同文本7篇
- 个人房产销售合同5篇
- 骨科围手术期患者护理制度
- 公司法务课件
- 北美128个护理诊断
- 2025高考英语全国II卷试题分析及备考策略指导课件
- 人口老龄化带来的公共卫生挑战-深度研究
- 全国公开课大赛一等奖小学二年级下册数学新人教版《除法的初步认识-除法》课件
- 2025年度宠物赛事组织与赞助合同4篇
- 内容理解与概括【知识精研】 中考语文一轮复习精讲专练
- 2025年发展对象考试题库附含答案
- 牙科设备供应及后续服务方案
- 物流公司驾驶员管理的规章制度
- 【MOOC】大学物理-电磁学-北京理工大学 中国大学慕课MOOC答案
- 外包服务合作协议
评论
0/150
提交评论