小。速度很快。可靠。
选择任意三个选项。

SQLite中的隔离

数据库的“隔离”属性决定何时更改一个操作的数据库对其他并发操作可见。

数据库连接之间的隔离

如果使用两个不同的数据库连接(两个不同方形3返回的对象单独呼叫sqlite3_open())和两个数据库连接没有共享缓存,则读者只能查看编写器提交的完整事务。部分更改作者所写的未经承诺的内容对读者来说是看不见的。无论两个数据库连接是否在同一线程,在同一进程的不同线程中,或在不同的流程。这个是SQL数据库系统的常见和预期行为。

上一段也是正确的(单独的数据库连接是相互隔离)共享缓存模式只要read_uncommitted杂注保持关闭状态读取未提交的杂注默认情况下处于关闭状态,因此如果应用程序未执行任何操作,它将保持关闭状态。因此,除非read_uncommitted杂注已使用要更改默认行为,请更改一个数据库连接对共享相同的缓存,直到写入程序提交其事务。

如果两个数据库连接共享同一缓存,并且读取器具有启用了read_uncommitted杂注,那么读者将能够在writer事务提交之前,查看writer所做的更改。联合使用共享缓存模式read_uncommitted杂注是一个数据库连接可以看到未提交更改的唯一方式在不同的数据库连接上。在所有其他情况下数据库连接彼此完全隔离。

除以下情况外共享缓存数据库连接PRAGMA读_未提交打开时,SQLite中的所有事务都会显示“可序列化”隔离。SQLite实现可序列化事务通过实际序列化写入。只能有一个作家每次发送到SQLite数据库。可以有多个数据库连接同时打开,所有这些数据库连接都可以写入到数据库文件,但他们必须轮流执行。SQLite使用锁自动序列化写入;这不是什么使用SQLite的应用程序需要考虑。

隔离和并发

SQLite使用实现隔离和并发控制(以及原子性)与数据库文件出现在同一目录中的临时日志文件。有两种主要的“日记模式”。旧的“回滚模式”对应于使用“DELETE”、“PERSIST”、,或“TRUNCATE”选项日志模式杂注。在回滚模式下,更改直接写入数据库文件,同时构造了一个单独的回滚日志文件,可以恢复如果事务回滚,数据库将恢复到其原始状态。回滚模式(特别是DELETE模式,这意味着回滚日志在每个事务结束时从磁盘中删除)是当前的默认行为。

版本3.7.0(2010-07-21), SQLite还支持“WAL模式“.在WAL模式下,更改不会写入原始数据库文件。相反,更改进入单独的“提前写日志”或“WAL”文件。稍后,在交易之后提交时,这些更改将从WAL文件移回名为“检查点”的操作中的原始数据库。WAL模式为通过运行“PRAGMA journal_mode=WAL".

在回滚模式下,SQLite通过锁定数据库来实现隔离文件并防止其他数据库连接进行任何读取而每个写事务都在进行中。读卡器可以在写入开始时,在任何内容之前处于活动状态刷新到磁盘,而所有更改仍保留在写入程序的私有内存空间。但在对数据库文件进行任何更改之前在磁盘上,所有读卡器都必须(暂时)被逐出,才能给写卡器以独占方式访问数据库文件。因此,禁止读者看到不完整的内容事务,因为在事务正在写入磁盘。仅在交易完成后允许读卡器完全写入并同步到磁盘并提交返回数据库。因此,读者永远没有机会看到部分内容书面变更。

WAL模式允许同时读取和写入。它可以做到这一点,因为更改不会覆盖原始数据库文件,而是到单独的预写日志文件中。这意味着读者可以继续阅读从原始数据库文件中读取旧的、原始的、未更改的内容同时,写入程序正在向预写日志追加内容。WAL模式,SQLite表现出“快照隔离”。当读取事务开始时,该读者继续看到数据库的不变“快照”文件,因为它在读取事务启动时存在。读取事务执行时提交的任何写入事务active对read事务仍然不可见,因为reader查看前一时刻的数据库文件快照。

示例:假设有两个数据库连接X和Y.X启动读取事务使用开始后跟一个或多个选择声明。然后Y跑过来更新语句来修改数据库。X随后可以执行选择与Y修改但X将看到旧的未修改条目,因为Y的更改都是X持有读取事务时,X不可见。如果X想看Y所做的更改,然后X必须结束其读取事务,并且开始一个新的(通过运行承诺接着是另一个开始.)

另一个示例:X使用以下命令启动读取事务开始选择,然后Y使用对数据库进行更改更新然后X尝试生成使用更改数据库更新。X试图升级其从读取事务到写入事务的事务失败SQLITE_BUSY_SNAPSHOT数据库错误,因为数据库的快照X查看的不再是数据库的最新版本。如果X是允许写入时,它将分叉数据库文件的历史记录,这是SQLite不支持的内容。为了让X写入数据库,它必须首先释放其快照(使用回降例如)然后使用后续事务启动新事务开始.

如果X启动一个最初只读取但X知道的事务最终会想写作而不想被打扰由于另一个连接而产生的可能SQLITE_BUSY_SNAPSHOT错误排在前面,然后X可以发出立即开始开始它的交易而不仅仅是一个普通的开始。这个立即开始命令继续执行并启动写事务,从而阻止所有其他作家。如果立即开始操作成功,则否该事务中的后续操作将永远失败SQLITE_BUSY数据库错误。

同一数据库连接上的操作之间没有隔离

SQLite在单独的数据库中提供操作之间的隔离连接。但是,以下操作之间没有隔离发生在同一数据库连接中。

换句话说,如果X使用立即开始然后发布一个或多个更新,删除、和/或插入语句,然后这些更改对后续语句可见选择声明在数据库连接X中计算的。选择关于的声明不同的数据库连接Y在X之前不会显示任何更改事务提交。但是选择X中的语句将显示更改在提交之前。

在单个数据库连接X中,SELECT语句总是可以看到在开始SELECT之前完成的数据库更改声明,无论是否提交。和SELECT语句显然没有看到SELECT语句后发生任何更改完成。但是,当SELECT语句正在运行?如果启动SELECT语句sqlite3_step()接口逐步完成大约一半的输出,然后更新语句由修改表的应用程序运行SELECT语句正在读取,然后更多调用sqlite3_step()是制造的完成SELECT语句?SELECT的后续步骤语句是否看到UPDATE所做的更改?答案是此行为未定义。特别是,无论SELECT语句是否看到并发更改取决于SQLite的哪个版本运行时,数据库文件的模式,无论是否分析以及查询的详细信息。在某些情况下,这可能取决于数据库文件的内容。没有好办法知道SELECT语句是否会看到对数据库所做的更改在SELECT语句启动后通过相同的数据库连接。因此,开发人员应该努力避免编写应用程序对这种情况下会发生什么做出假设。

如果应用程序对单个表发出SELECT语句,如"SELECT rowid,*FROM表WHERE。。。“并开始逐步通过该语句的输出使用sqlite3_step()并检查每个行,则应用程序可以安全地删除当前行或任何使用“DELETE FROM table WHERE rowid=?”的前一行。它也很安全(从某种意义上说,它不会损害数据库)删除预期稍后在查询中出现但尚未出现的行出现了。但是,如果删除了未来的行,则可能会发生以下情况该行出现在随后的sqlite3_step()之后,即使它已经据称已被删除。或者可能不会。这种行为没有定义。应用程序可以当SELECT语句为正在运行,但是否显示新行在随后的sqlite3_step()中,查询的s未定义。以及应用程序可以更新当前行或任何之前的行,但这样做可能会导致该行将在随后的sqlite3_step()中重新出现。只要应用程序准备处理这些模糊性它们本身是安全的,不会损害数据库文件。

在前两段中,有两个数据库连接有相同的共享缓存以及启用了PRAGMA读_未提交被认为是相同的数据库连接。

总结

  1. SQLite中的事务是SERIALIZABLE。

  2. 在一个数据库连接中所做的更改对所有其他数据库都不可见提交之前的连接。

  3. 查询可以查看在同一数据库连接上完成的所有更改在查询开始之前,无论这些更改是否发生已提交。

  4. 如果查询后同一数据库连接发生更改开始运行,但在查询完成之前,是否否则查询将看到这些更改。

  5. 如果查询后同一数据库连接发生更改开始运行,但在查询完成之前,查询可能会返回更改了多次的行,或者它可能返回以前的行删除。

  6. 对于前四项,两个数据库连接使用相同的共享缓存以及使PRAGMA读_未提交视为相同的数据库连接,而不是单独的数据库连接。