Small. Fast. Reliable.
Choose any three.
SQLite共享缓存模式

1. SQLite共享缓存模式

版本3.3.0(2006-01-11)开始,SQLite包括一种特殊的“共享缓存”模式(默认情况下禁用),旨在用于嵌入式服务器。如果启用了共享缓存模式,并且线程建立了到同一数据库的多个连接,则这些连接共享单个数据和架构缓存。这样可以大大减少系统所需的内存和IO数量。

3.5.0版(2007-09-04)中,修改了共享缓存模式,以便可以在整个进程中共享同一缓存,而不仅仅是在单个线程中共享。在进行此更改之前,在线程之间传递数据库连接受到限制。这些限制在3.5.0更新中已删除。本文档介绍了自3.5.0版开始的共享缓存模式。

在某些情况下,共享缓存模式会更改锁定模型的语义。本文档描述了详细信息。 假定对基本的SQLite锁定模型有基本的了解(有关详细信息,请参见 SQLite版本3中的文件锁定和并发性)。

2.共享缓存锁定模型

从外部看,从另一个进程或线程的角度来看,使用共享缓存的两个或多个数据库连接显示为单个连接。其他地方介绍了用于在多个共享缓存或常规数据库用户之间进行仲裁的锁定协议。

图1

图1描述了一个示例运行时配置,其中已建立了三个数据库连接。连接1是普通的SQLite数据库连接。连接2和3共享高速缓存正常的锁定协议用于序列化连接1和共享高速缓存之间的数据库访问。本节的其余部分介绍了用于对连接2和3对共享缓存的访问进行序列化的内部协议(或不,请参见下面的“读-未提交隔离模式”)。

共享缓存锁定模型分为三个级别:事务级别锁定,表级别锁定和架构级别锁定。在以下三个小节中对它们进行了描述。

2.1。交易级别锁定

SQLite连接可以打开两种事务,即读取和写入事务。这不是显式完成的,事务隐式地是一种读事务,直到它首先写入数据库表为止,这时它就变成了写事务。

与单个共享缓存的最多一个连接可以在任何时候打开一个写事务。这可以与任何数量的已读事务共存。

2.2。表级锁定

当两个或多个连接使用共享缓存时,锁将用于按表对并发访问尝试进行序列化。表支持两种类型的锁,“读锁”和“写锁”。将锁授予连接-在任何时候,每个数据库连接在每个数据库表上都具有读锁,写锁或无锁。

在任何时候,单个表可以具有任意数量的活动读锁定或单个活动写锁定。要从表中读取数据,连接必须首先获得读取锁。要写入表,连接必须在该表上获得写锁。如果无法获得所需的表锁,则查询失败,并且SQLITE_LOCKED返回给调用方。

一旦连接获得表锁,则直到当前事务(读或写)结束后才释放该表锁。

2.2.1。读未提交隔离模式

通过使用read_uncommitted编译指示将隔离级别从序列化(默认)更改为read-uncommitted ,可以稍微修改上述行为 。

如上所述,处于读未提交模式的数据库连接在尝试从数据库表读取之前不会尝试获取读锁。如果在读取表时另一个数据库连接修改了一个表,这可能导致查询结果不一致,但是这也意味着,由处于未读提交模式的连接打开的读取事务既不能阻塞也不能被任何其他连接阻塞。

读未提交模式对写入数据库表所需的锁没有影响(即,读未提交的连接仍必须获得写锁,因此数据库写操作仍可能被阻塞或被阻塞)。另外,未提交读模式对 下面列举的规则所需的sqlite_schema锁无效(请参见“模式(sqlite_schema)级别锁定”部分)。

  / *设置未提交读标志的值:
  **
  ** True->将连接设置为未提交读模式。
  ** False->将连接设置为序列化(默认)模式。
  * /
  PRAGMA read_uncommitted = <布尔值>;

  / *检索未提交的标志的当前值* /
  PRAGMA read_uncommitted;

2.3。模式(sqlite_schema)级别锁定

所述sqlite_schema表支持共享高速缓冲存储器读取和写锁以相同的方式,因为所有的其它数据库表(参见上面的描述)。以下特殊规则也适用:

3.与线程相关的问题

在启用共享缓存模式的SQLite版本3.3.0至3.4.2中,数据库连接只能由调用sqlite3_open()的线程创建。一个连接只能与同一线程中的另一个连接共享缓存。从SQLite 3.5.0(2007-09-04)版本开始删除了这些限制 。

4.共享缓存和虚拟表

在旧版本的SQLite中,共享缓存模式不能与虚拟表一起使用。SQLite版本3.6.17(2009-08-10)中删除了此限制。

5.启用共享缓存模式

共享缓存模式在每个进程的基础上启用。使用C接口,以下API可用于全局启用或禁用共享缓存模式:

int sqlite3_enable_shared_cache(int);

每次调用sqlite3_enable_shared_cache()都会影响使用sqlite3_open()sqlite3_open16()sqlite3_open_v2()创建的后续数据库连接。已经存在的数据库连接不受影响。每次调用sqlite3_enable_shared_cache()都会覆盖同一进程中的所有先前调用。

通过使用SQLITE_OPEN_SHAREDCACHESQLITE_OPEN_PRIVATECACHE标志第三个参数,使用sqlite3_open_v2()创建的单个数据库连接可以选择参与或不参与共享缓存模式。使用这些标志之一将覆盖sqlite3_enable_shared_cache()建立的全局共享缓存模式设置。最多只能使用一个标志。如果在sqlite3_open_v2()的第三个参数中同时使用了SQLITE_OPEN_SHAREDCACHE和SQLITE_OPEN_PRIVATECACHE标志, 则该行为未定义。

使用URI文件名时,“ cache”查询参数可用于指定数据库是否将使用共享缓存。使用“ cache = shared”启用共享缓存,使用“ cache = private”禁用共享缓存。使用URI查询参数来指定数据库连接的缓存共享行为的功能允许在ATTACH语句中控制缓存共享。例如:

附加'file:aux.db?cache = shared'AS aux;

6.共享的缓存和内存数据库

从SQLite版本3.7.13(2012-06-11)开始,可以在内存数据库中使用共享缓存 ,前提是该数据库是使用URI filename创建的。为了向后兼容,如果使用未经修饰的名称“:memory:”打开数据库,则始终禁用内存数据库的共享缓存。在3.7.13版之前,内存数据库中的共享缓存始终被禁用,无论使用的数据库名称,当前系统共享的缓存设置,查询参数或标志如何。

为内存数据库启用共享缓存可使同一进程中的两个或多个数据库连接访问同一内存数据库。当与该数据库的最后一个连接关闭时,共享缓存中的内存数据库将自动删除,并回收内存。