首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

SQLite Shared-Cache Mode

1. SQLite共享缓存模式

2.共享缓存锁定模型

2.1.事务级别锁定

2.2.表级锁定

2.2.1.Read-Uncommitted隔离模式

2.3架构(sqlite_master)级别锁定

3.线程相关问题

4.共享缓存和虚拟表

5.启用共享高速缓存模式

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

版本3.3.0(2006-01-11)开始,SQLite包含专门用于嵌入式服务器的“共享缓存”模式(默认情况下禁用)。如果启用共享高速缓存模式并且一个线程建立到同一个数据库的多个连接,则这些连接共享一个数据和模式高速缓存。这可以显着减少系统所需的内存和IO数量。

版本3.5.0(2007-09-04)中,修改了共享高速缓存模式,以便可以在整个进程间共享相同的高速缓存,而不是在单个线程内共享。在此更改之前,线程之间传递数据库连接时存在限制。这些限制在3.5.0更新中被删除。本文档介绍3.5.0版本之后的共享缓存模式。

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

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

| ​ |

|:----|

图1

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

共享缓存锁定模型有三个级别,事务级别锁定,表级锁定和模式级别锁定。它们在以下三个小节中进行介绍。

2.1.事务级别锁定

SQLite连接可以打开两种事务,读取和写入事务。这不是明确的,一个事务在它首次写入数据库表之前是隐式的读事务,在这一点上它变成了写事务。

至多一个连接到单个共享缓存的任何时候都可以打开写入事务。这可能与任何数量的读取事务共存。

2.2.表级锁定

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

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

一旦连接获得一个表锁,它就不会被释放,直到当前事务(读或写)结束。

2.2.1.Read-Uncommitted隔离模式

通过使用read_uncommitted pragma将隔离级别从serialized(默认值)更改为read-uncommitted,可以稍微修改上述行为。

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

只读未提交模式对写入数据库表所需的锁没有影响(例如,读取未提交的连接仍必须获得写入锁,因此数据库写入可能仍会阻止或被阻止)。此外,read-uncommitted模式对下面枚举规则所需的sqlite_master锁没有影响(请参见“Schema(sqlite_master)Level Locking”一节)。

  /* Set the value of the read-uncommitted flag:
  **
  **   True  -> Set the connection to read-uncommitted mode.
  **   False -> Set the connection to serialized (the default) mode.
  */
  PRAGMA read_uncommitted = <boolean>;

  /* Retrieve the current value of the read-uncommitted flag */
  PRAGMA read_uncommitted;

2.3.架构(sqlite_master)级别锁定

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

  • 在访问任何数据库表或获取任何其他读或写锁之前,连接必须获得sqlite_master上的读锁定。
  • 在执行修改数据库模式的语句(即CREATE或DROP TABLE语句)之前,连接必须在sqlite_master上获得写入锁定。
  • 如果任何其他连接在任何附加数据库(包括缺省数据库,“main”)的sqlite_master表上持有写入锁定,则连接可能无法编译SQL语句。

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

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

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

int sqlite3_enable_shared_cache(int);

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

使用sqlite3_open_v2()创建的单个数据库连接可以通过使用SQLITE_OPEN_SHAREDCACHE或SQLITE_OPEN_PRIVATECACHE标记第三个参数来选择参与或不参与共享缓存模式。使用这些标志中的任何一个都会覆盖由sqlite3_enable_shared_cache()建立的全局共享缓存模式设置。不应该使用一个以上的标志; 如果在sqlite3_open_v2()的第三个参数中使用了SQLITE_OPEN_SHAREDCACHE和SQLITE_OPEN_PRIVATECACHE标志,则行为是未定义的。

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

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

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

为内存数据库启用共享高速缓存允许同一进程中的两个或更多数据库连接访问相同的内存数据库。共享缓存中的内存数据库会自动删除,并且在与数据库的最后一次连接关闭时会回收内存。

 SQLite在公共领域。

扫码关注腾讯云开发者

领取腾讯云代金券