浅析SQLite的锁机制和WAL技术
锁机制
SQLite基于锁来实现并发控制。SQLite的锁是粗粒度的,并不拥有PostgreSQL那样细粒度的行锁,这也使得SQLite较为轻量级。当一个连接要写数据库时,所有其它的连接都被锁住,直到写连接结束它的事务。
SQLite的数据库连接有5种状态:
状态 | 对应的锁 |
---|---|
未加锁 | — |
共享(shared) | 共享锁 |
预留(reserved) | 预留锁 |
未决(pending) | 未决锁 |
排它(exclusive) | 排它锁 |
SQL使用锁逐步提升机制,上面的表格从上到下,对应锁的等级逐步提升,等级越高权限就越大。
未加锁:
未和数据库建立连接、已建立连接但是还没访问数据库、已用BEGIN开始了一个事务但未开始读写数据库,处于这些情形时是未加锁状态。
共享:
连接需要从数据库中读取数据时,需要申请获得一个共享锁,如果获得成功,则进入共享状态。
预留:
连接需要写数据库时,首先申请一个预留锁,一个数据库同时只能有一个预留锁,预留锁可以与共享锁共存。获得预留锁后进入预留状态,这时会先在缓冲区中进行需要的修改、更新操作,操作后的结果依然保存在缓冲区中,未真正写入数据库。
未决:
连接从预留升为排它前,需要先升为未决,这时其它连接就不能获得共享锁了,但已经拥有共享锁的连接仍然可以继续正常读数据库,此时,拥有未决锁的连接等待其它拥有共享锁的连接完成工作并释放其共享锁后,提成到排它锁。
排它:
连接需要提交修改时,需要将预留锁升为排它锁,这时其它连接都无法获得任何锁,直到当前连接的排它状态结束。
一个连接读数据的流程如下:
一个连接写数据的流程如下:
死锁
在使用事务的情况下,SQLite的锁机制存在死锁的可能性。
见下面例子:
执行顺序 | 连接A | 连接B |
---|---|---|
1 | BEGIN; | |
2 | BEGIN; | |
3 | INSERT INTO foo VALUES (‘x’); | |
4 | SELECT * FROM foo; | |
5 | COMMIT; | |
6 | SQL error: database is locked | |
7 | INSERT INTO foo VALUES (‘x’); | |
8 | SQL error: database is locked |
执行顺序3:连接B要执行写操作,获得预留锁
执行顺序4:连接A要执行读操作,获得共享锁
执行顺序5:连接B要提交修改,预留锁升级为未决锁
执行顺序6:连接B想要升级为排它锁,必须先等待连接A释放共享锁
执行顺序7:连接A要执行写操作,需要获得预留锁
执行顺序8:连接A获得预留锁失败,必须先等待连接B释放未决锁
于是连接A和连接B相互等待对方,发生死锁。
可以通过正确的使用事务类型来解决以上死锁问题,这里不再陈述。
WAL技术
SQLite在3.7.0开始引入了WAL技术,全称叫Write Ahead Log(预写日志)。
其原理是:修改并不直接写入到数据库文件中,而是写入到另外一个称为WAL的文件中;如果事务失败,WAL中的记录会被忽略,撤销修改;如果事务成功,它将在随后的某个时间被写回到数据库文件中,提交修改。
WAL使用检查点将修改写回数据库,默认情况下,当WAL文件发现有1000页修改时,将自动调用检查点。这个页数大小可以自行配置。
WAL技术带来以下优点:
- 读写操作不再互相阻塞,一定程度上解决了SQLite在处理高并发上的性能瓶颈
- 大多数场景中,带来很大的性能提升
- 磁盘I/O行为更容易被预测
WAL也有一些缺点,不过在iOS开发中影响不大,除非数据达到GB级时,性能才会降低。
如何启用WAL:
如果是直接使用SQLite,需要设置如下编译指示:
PRAGMA journal_mode=WAL;
如果是使用Core Data,则已经默认开启了WAL模式。
http://liuduo.me/2016/04/02/sqlitelockandwal/
SQLite基于底层的锁原语设计了4种锁,分别是:
SHARED_LOCK 这是读操作锁, 多个进程可以同时持有该类型的锁,实现并发读操作.
RESERVED_LOCK 这是写操作锁,在给定时间内,只有一个进程可以持有该类型的锁.但是已经持有SHARED_LOCK读锁的其他进程,仍然可以进行读操作,其他进程也可以获得新的SHARED_LOCK读锁.
PENDING_LOCK 这是写操作锁,其他持有SHARED_LOCK锁的进程可以继续进行读操作,但是该锁将阻止其他进程获取新的SHARED_LOCK锁.
EXCLUSIVE_LOCK 这是写操作锁,在给定时间内,只有一个进程持有EXCLUSIVE_LOCK锁,这将阻止其他进程获取任何类型的锁.也就是说,获得该锁的前提是,其他进程没有持有任何锁.
对于SQLite层面的这4种类型的的锁,有2点需要说明的是:
这4种锁依照严格性是依次递增的, 锁之间的状态迁移是有一定顺序的,也是按照严格性进行依次状态迁移的.存在如下几种状态迁移的路径:
---------------------
作者:azurelaker
来源:CSDN
原文:https://blog.csdn.net/azurelaker/article/details/82708573
版权声明:本文为博主原创文章,转载请附上博文链接!
浅析SQLite的锁机制和WAL技术的更多相关文章
- InnoDB的锁机制浅析(五)—死锁场景(Insert死锁)
可能的死锁场景 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意 ...
- InnoDB的锁机制浅析(四)—不同SQL的加锁状况
不同SQL的加锁状况 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/ ...
- InnoDB的锁机制浅析(三)—幻读
文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意向锁) Inno ...
- InnoDB的锁机制浅析(二)—探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意向锁)
Record锁/Gap锁/Next-key锁/插入意向锁 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Recor ...
- InnoDB的锁机制浅析(一)—基本概念/兼容矩阵
InnoDB锁的基本概念 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Record锁/Gap锁/Next-key ...
- InnoDB的锁机制浅析(All in One)
目录 InnoDB的锁机制浅析 1. 前言 2. 锁基本概念 2.1 共享锁和排它锁 2.2 意向锁-Intention Locks 2.3 锁的兼容性 3. InnoDB中的锁 3.1 准备工作 3 ...
- PostgreSQL 锁机制浅析
锁机制在 PostgreSQL 里非常重要 (对于其他现代的 RDBMS 也是如此).对于数据库应用程序开发者(特别是那些涉及到高并发代码的程序员),需要对锁非常熟悉.对于某些问题,锁需要被重点关注与 ...
- MySQL锁机制浅析
MySQL使用了3种锁机制 行级锁,开销大,加锁慢,会出现死锁,发生锁冲突的概率最高,并发度也最高 表级锁,开销小,加锁快,不会出现死锁,发生锁冲突的概率最低,并发度最低 页级锁,开销和加锁时间界于表 ...
- 分布式锁1 Java常用技术方案
前言: 由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.所以自己结合实际工作中的一些经验和网上看到的一些资 ...
随机推荐
- Gvim 和vim 有什么区别
Gvim 和vim 有什么区别 Gvim是windows的 vim是linux的黑色的命令符 Gvim是单独的窗口下的vim,像notepad一样. vim就是在黑乎乎的cmd窗口下的编辑器.wind ...
- Github被微软收购,这里整理了16个替代品
微软斥资75亿美元收购以后,鉴于微软和开源竞争的历史,很多开发者都感到惊恐.毕竟,互联网上最大的一块可以自由的净土被微软染指,宝宝不开森.如果你真的担心微软会对Github有所动作,那么这里我列举了1 ...
- 如何在Promise链中共享变量?
译者按: 使用Promise写过异步代码的话,会发现在Promise链中共享变量是一个非常头疼的问题,这也是Async/Await胜过Promise的一点,我们在Async/Await替代Promis ...
- linux服务器重启指令
一.Linux 的五个重启命令 1.shutdown 2.poweroff 3.init 4.reboot 5.halt 二.五个重启命令的具体说明 shutdown reboot 在linux下一些 ...
- 使用JavaScript获取URL中的参数(两种方法)
本文给大家分享两种方法使用js获取url中的参数,其中方法二是使用的正则表达式方法,大家可以根据需要选择比较好的方法,废话不多说了,直接看详细介绍吧. 方法一: //取url参数 var type = ...
- JS之onunload、onbeforeunload事件详解
简介 onunload,onbeforeunload都是在刷新或关闭时调用,可以在<script>脚本中通过 window.onunload来调用.区别在于onbeforeunload在o ...
- 2017-11-07 中文代码示例之Angular入门教程尝试
"中文编程"知乎专栏原址 原文: 中文代码示例教程之Angular尝试 为了检验中文命名在Angular中的支持程度, 把Angular官方入门教程的示例代码中尽量使用了中文命名. ...
- [C语言]易错知识点、小知识点复习(1)
1. 计算机只能识别由0和1组成的二进制指令,需要将用高级语言(如C.C++)编写的源程序(.c..cpp)编译成二进制目标文件(.obj).一个程序可以根据需要写在不同的文件里,编译是以文件为单位进 ...
- Tars 负载均衡
// 传入主控地址,在 db_tars t_registry_info 表中 Communicator communicator = CommunicatorFactory.getInstance() ...
- 小程序实践(二):swiper组件实现轮播图效果
swiper组件类似于Android中的ViewPager,实现类似轮播图的效果,相对于Android的Viewpager,swiper实现起来更加方便,快捷. 效果图: 首先看下swiper支持的属 ...