相关概念
Connection 和 Statements。Connection是负责在一个事务中建立连接池,Statement包括sql语句的解析、执行语句的资源、指向硬盘记录的游标和参数。
每一个数据库有一个B-Tree(B树)对象,而B-Tree对象又持有一个pager对象。当用户从发起一条sql语句去操作数据库,这时Statement调用游标(Cursor),游标去B-Tree里,委托pager把disk上的数据取出放到缓冲区中。Pager的主要职责是管理内存缓存和page、事务管理、锁和崩溃事件。
sqlite创建物理文件也是懒加载,只有在数据写入时才会创建文件,否则只是一个空文件,nothing in it~一个连接只会在一个事务下
连接数据库的生命周期
连接数据库
执行事务
关闭连接
预处理查询
这个步骤是SQLite执行所有sql命令的方式,预处理把分析器、分词器、代码生成器把Statement编译成VDBE字节码,编译器会生成sqlite3_stmt句柄。
由sqlite3_prepare去编译字节码,sqlite3_step启动虚拟机去遍历物理文件
事务
SQLite里锁的状态包含以下几个:
UNLOCKED 未加锁
SHARED 共享
RESERVED 保留
PENDING 未决
EXCLUSIVE 排他
SQLite使用的是粗放型的锁机制。首先读数据只会用到共享锁(SHARED),多个连接可以共享并保持共享锁。当这时有一个写操作进来时,会获取保留锁(RESERVED),一个连接仅且只有一个保留锁,这时候数据库可接受其他新的读操作再获取共享锁,但不影响已经获取共享锁的读操作。然后等到所有读操作完成之后,保留锁会提升到未决锁(PENDING),到这个阶段数据库会阻止所有新获取共享锁的操作,但已有共享锁的操作还能继续进行,等到所有共享锁完成操作之后,未决锁会提升到排他锁(EXCLUSIVED),这时才是真正写入数据库文件。
SQLite可以高效的处理在同一时刻的多个读连接和一个写连接
为什么要用EXCUSIVE锁?
主要处于并发性的考虑,由于SQLite只有库级的EXCUSIVE锁,如果当开始进行写操作时就是用这个锁,然后再进行实际的数据更新,那么并发性的性能会大大降低。所以SQLite当获取到RESERVED锁时,其他进程可以同时进行读操作,直到写入数据库一刻才锁库。
以下是sqlite状态锁的流程图:
5AB90474-21D3-4D47-B8CC-23A11F6A0EC6.png