sqlite中的锁及概念误区

来源:互联网 发布:名片设计app软件 编辑:程序博客网 时间:2024/05/22 11:40

前言


谈及sqlite,首先想到的必定是小巧便捷,尤其是嵌入式开发,相比较而言,对于sqlite的并发,大致都是这么说的(以下不代表个人观点)

     SQLite作为一款小型的嵌入式数据库,本身没有提供复杂的锁定机制,无法内部管理多路并发下的数据操作同步问题,更谈不上优化,     所以涉及到多路并发的情况,需要外部进行读写锁控制,否则SQLite会返回SQLITE_BUSY错误,以驳回相关请求。


需要澄清一下,这种说法自身就有问题,就数据库而言,处理的并发实际上分为读并发,写并发,与读写并发,我们广义上说的并发实际上指的是读写并发,要了解这些,我们还需要先了解一下sqlite中的锁.


sqlite中的锁


sqlite中一共有五种锁分别是

        未加锁(UNLOCKED)

        文件没有持有任何锁,即当前数据库不存在任何读或写的操作。其它的进程可以在该数据库上执行任意的读写操作。此状态为缺省状态。

        共享锁(SHARED)

         在此状态下,该数据库可以被读取但是不能被写入。在同一时刻可以有任意数量的进程在同一个数据库上持有共享锁,因此读操作是并发的。换句话说,只要有一个或多个共享锁处于活动状态,就不再允许有数据库文件写入的操作存在。

        保留锁(RESERVED)

         假如某个进程在将来的某一时刻打算在当前的数据库中执行写操作,然而此时只是从数据库中读取数据,那么我们就可以简单的理解为数据库文件此时已经拥有了保留锁。当保留锁处于活动状态时,该数据库只能有一个或多个共享锁存在,即同一数据库的同一时刻只能存在一个保留锁和多个共享锁. 需要说明的是update操作 实际上是一个读操作加一个写操作

        未决锁(PENDING)

         PENDING锁的意思是说,某个进程正打算在该数据库上执行写操作,然而此时该数据库中却存在很多共享锁(读操作),那么该写操作就必须处于等待状态,即等待所有共享锁消失为止,与此同时,新的读操作将不再被允许,以防止写锁饥饿的现象发生。在此等待期间,该数据库文件的锁状态为PENDING,在等到所有共享锁消失以后,PENDING锁状态的数据库文件将在获取排他锁之后进入EXCLUSIVE状态。

        排它锁(EXCLUSIVE)

        在执行写操作之前,该进程必须先获取该数据库的排他锁。然而一旦拥有了排他锁,任何其它锁类型都不能与之共存。因此,为了最大化并发效率,SQLite将会最小化排他锁被持有的时间总量。


读操作锁变化


       了解了sqlite的锁之后 我们再来看针对读写操作,sqlite内部的锁变化



读操作的目的是获取共享锁shared从而来访问数据   那么 在获得共享锁(SHARED)之前  

首先检查是否有排它锁(EXCLUSIVE)  如果有 则说明sqlite正在进行写入操作 为保障数据一致 所以无法获取共享锁(SHARED)

如果没有 再检查是否有未决锁(PENDING)如果有 表示当前有准备进行的写操作并阻止共享锁(SHARED)的获取

如果检测不到上述两个锁 将获得共享锁(SHARED)  读取数据 然后释放共享锁


写操作锁变化


对于写操作,写操作的目的是为了获得 排它锁(EXCLUSIVE) 独占数据库从而一致性,其内部锁变化如下



首先  检查数据库是否有保留锁(RESERVED)排它锁(EXCLUSIVE)  如果有 则说明在此次写操作之前还准备有或者正在进行一次写操作

此时如法获取排它锁(EXCLUSIVE)  如果没有 则获取未决锁(PENDING)   当未决锁(PENDING)获得时,将无法再获取到共享锁(SHARED),也就是说sqlite此时已经不再处理读请求

在持有未决锁(PENDING)期间  将会不断询问内部是否还有共享锁(SHARED)  当等待所有共享锁(SHARED)消失  当所有共享锁(SHARED)消失时 此时锁状态将由未决锁(PENDING)切换至排它锁(EXCLUSIVE) 并写入数据    当排它锁(EXCLUSIVE)激活时 阻止任何类型的其它锁获取 直至写入完毕并释放排它锁(EXCLUSIVE)


总结

最后我们来总结一下

1.当有写操作时,其他读操作会被驳回2.当有写操作时,其他写操作会被驳回3.当开启事务时,在提交事务之前,其他写操作会被驳回4.当开启事务时,在提交事务之前,其他事务请求会被驳回5.当有读操作时,其他写操作会被驳回6.读操作之间能够并发执行
0 0