SQLite的数据类型
SQLite支持的数据类型有:
- INTEGER:有符号整形
存储时将根据值大小占用1,2,3,4,6,8字节空间,读取时统一转换成8字节有符号整型。
- REAL:浮点型,占用8字节;
- TEXT:字符串;
- BLOB:二进制数据;
- NULL:空值。
与大多数其他数据库系统不一样,SQLite不强制约束数据类型(除了INTEGER PRIMARY KEY column)。即使声明为INTEGER类型的字段,也可以插入TEXT、BLOB等类型数据,数据库引擎会尝试自动将值转换为适当的数据类型并存储。参考:Datatypes In SQLite Version 3
SQLite重要的数据结构
Connection
Connection代表在一个事务环境下的一个单独的数据库连接。每一个Connection用sqlite3结构表示,通过sqlite3_open系列接口获取。
Statement
Statement表示一个编译过的SQL语句,包含了执行一个SQL命令所需要一切资源,包括指向磁盘记录的B-tree游标,以及参数等。只要SQL语句不变,对应的Statement可以重复使用,此时可以将Statement缓存以提高效率。Statement在代码中对应sqlite3_stmt结构,通过sqlite3_prepare_v2系列接口获取。
B-tree和Pager
每一个Connection可以包含多个数据库对象,每一个数据库对象都有一个B-tree对象,一个B-tree对应一个pager对象。pager负责读写数据库,管理内存缓存和页,以及管理事务、锁和回滚恢复等。
SQLite内置系统表SQLITE_MASTER,包含数据库中所有表信息。
SQLite的文件锁状态
#define NO_LOCK 0
#define SHARED_LOCK 1
#define RESERVED_LOCK 2
#define PENDING_LOCK 3
#define EXCLUSIVE_LOCK 4
如上,SQLite数据库文件有5种锁状态,实现了线程读写互斥。
- NO_LOCK
数据库此时没有读写操作。
- SHARED_LOCK
数据库可以多线程读取但不能写入。
- RESERVED_LOCK
预留锁,表示准备向数据库写入数据。当一个连接进入RESERVED状态时,pager就开始初始化回卷日志(rollback journal)文件。
- PENDING_LOCK
表示即将提交写事务,将等待其他读线程释放SHARED锁。一个线程持有PENDING锁后,其他线程就不能获取SHARED锁。只要等所有读线程释放SHARED锁后,才能进入EXCLUSIVE状态。
- EXCLUSIVE_LOCK
写入数据库。进入这个状态后,其他任何线程都不能访问数据库文件。为保证效率,EXCLUSIVE_LOCK状态的时间越短越好。
SQLite的线程模式
SQLite内部有两个锁开关:bCoreMutex和bFullMutex。他们的作用分别是:
- bCoreMutex=1:保证不同Connection不会对数据库进行修改;
- bFullMutex=1:保证了一个Connection不会同时对数据库修改;
由bCoreMutex和bFullMutex控制了SQLite的三种线程模式:
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */
case SQLITE_CONFIG_SINGLETHREAD: {
/* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to
** Single-thread. */
sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */
sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */
break;
}
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */
case SQLITE_CONFIG_MULTITHREAD: {
/* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to
** Multi-thread. */
sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */
sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */
break;
}
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */
case SQLITE_CONFIG_SERIALIZED: {
/* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to
** Serialized. */
sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */
sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */
break;
}
#endif
- Single-thread
在Single-thread模式下,SQLite会关闭bCoreMutex和bFullMutex开关,在多线程操作下不安全。如果调用方可以保证所有操作均是在单线程环境中进行,则可以选择Single-thread模式,可以减少线程锁的开销。
- Multi-thread
在Multi-thread模式下,bCoreMutex打开,bFullMutex关闭。此时,只要保证单个Connection不会被多个线程同时使用就是安全的。
- Serialized
在Serialized模式下,bCoreMutex和bFullMutex都是打开的,SQLite可以不受限制地被多个线程安全使用(支持使用多个Connection,每个Connection都可以多线程读写),但性能也会受到影响。
设定SQLite的线程模式
三个地方的设定都会影响到SQLite的实际运行线程模式:
- SQLITE_THREADSAFE编译宏
SQLITE_THREADSAFE=0:默认启用Single-thread;
SQLITE_THREADSAFE=2:默认启用Multi-thread;
SQLITE_THREADSAFE=1:默认启用Serialized。
- sqlite3_open_v2设定
sqlite3_open_v2接口的flags参数可以指定线程模式:
SQLITE_OPEN_NOMUTEX:没有指定单线程模式的情况下,对应Multi-thread模式。
SQLITE_OPEN_FULLMUTEX:没有指定单线程模式的情况下,对应Serialized模式。
- sqlite3_config设定
SQLITE_CONFIG_SINGLETHREAD
SQLITE_CONFIG_MULTITHREAD
SQLITE_CONFIG_SERIALIZED
如果在编译时不是设定SQLITE_THREADSAFE=0,可以在初始化前调用sqlite3_config或在sqlite3_open时修改线程模式。sqlite3_config的设定,仅在初始化之前(sqlite3_open或sqlite3_initialize执行前)有效。
如果编译时设定SQLITE_THREADSAFE=0,则只能使用单线程模式。
SQL语法的支持
SQLite默认支持常用的SQL语句,目前已知的case有:
- 支持json扩展
需开启SQLITE_ENABLE_JSON1编译选项。可以存储JSON字符串并查询JSON内容:
SELECT timestamp, json_extract(column, \"$.key\") FROM event;
- DELETE等操作不支持LIMIT TOP子句
开启SQLITE_ENABLE_UPDATE_DELETE_LIMIT编译选项未能解决问题,可以采取其它语句变相解决。
留言板