内容简介:事务定义了一组SQL语句的边界,这组SQL语句要么都执行,要么都不执行,事务保证了数据库完整性中的原子性。事务与数据库锁是紧密相关的,Sqlite用锁来保证事务的并发和执行顺序。在讲解事务的原理之前,我们先看看事务相关的API,主要有三个:我们首先来看看回滚,假设有这样的一个Table
前言
事务定义了一组 SQL 语句的边界,这组SQL语句要么都执行,要么都不执行,事务保证了数据库完整性中的原子性。事务与数据库锁是紧密相关的,Sqlite用锁来保证事务的并发和执行顺序。
在讲解事务的原理之前,我们先看看事务相关的API,主要有三个:
-
begin transaction
开始一个事务。其中,transaction可省略,直接写begin
即可。 -
rollback
回滚。 -
commit
提交
我们首先来看看回滚,假设有这样的一个Table
id name phone ---------- ---------- ---------- 10001 Leo 1234567890
接着,我们来试试回滚
//开始事务 sqlite> begin; //插入一条数据 sqlite> insert into person(id,name,phone) values(10002,"Lina","12345671"); //查询,数据确实多了一行 sqlite> select * from person; id name phone ---------- ---------- ---------- 10001 Leo 1234567890 10002 Lina 12345671 //回滚 sqlite> rollback; //插入的数据被删除 sqlite> select * from person; id name phone ---------- ---------- ---------- 10001 Leo 1234567890
提交也类似,这样的语法结构即可:
begin; //SQL语句 commit;
事务的存在保证了数据库的的原子性,比如在数据写入的时候出现异常(断电等原因),待写入的数据不会丢失。
多链接模型
常见的模型:一个数据库文件,多个连接,每个连接有自己的语句。
一些名词的解释:
Connection - 连接,表示到数据库连接和事务的上下文,对应C接口中的 sqlite 3类型指针。一个数据库文件可以同时存在多个connection。
statement - 语句。 语句对象表示一个编译过的SQL语句,在内部由VDBE字节码来表示。VDBE全称是(Virtual DataBase Engine),也就是Sqlite虚拟机。一个这样的SQL语句select * from Table,在SQLite中是先要编译成VDBE字节码才能执行的。
每个连接都对应着一个B-Tree和Pager。连接直接操作B-Tree来读和写数据。当一个连接需要读取数据库文件的某一页的时候,这一页必须先加载到内存里,这时候B-Tree操作Pager进行页面读取,同时进行缓存。由于数据库要保证ACID,所以Pager还负责缓存管理以及回滚日志的维护。
OS Interface。 操作系统层API,比如Windows/MacOS对于文件的操作API是不一样的,这一层进行了封装,保证上层调用的统一。
Journal,日志文件,用于回滚。
事务是由Pager模块管理的,当一个事务开始( begin
)后,遇到了更改数据库的语句( update
, insert
, delete
),会首先操作当前连接的Pager,然后创建回滚日志文件,等到事务提交( commit
),Pager才会把整个事务的修改同步到数据库文件里。
在写文件的时候,无法避免的要锁数据库文件,锁数据库文件后,其他连接就无法读/写数据库。事务这种延迟和批量写入的方式,能够最大限度的提高数据库的并发性能。
当两个连接同时操作数据库进行读写的时候,SQLITE如何保证事务的正确性,以及如何保证读和读是可以并发的呢?答案是不同优先级的锁。
锁
大多数时候,锁的持续时间和事务是一样的,虽然并不是同时开始,但是总是一起结束。
Sqlite采用粗粒度的锁。当一个连接尝试写数据库的时候,所有其他连接都被锁住,直到写连接结束它的事务。Sqlite有一个加锁表,用来帮助不同的写数据库都能在最后一刻加锁。
状态:
-
UNLOCKED 未加锁
-
SHARED 共享锁
-
RESERVED 预留锁
-
PENDING 未决锁
-
EXCLUSIVE 排它锁
每个数据库连接同时只能处于一个状态 ,多个连接可以同时处于共享锁状态,哪怕有一个共享锁没有被释放,都不允许往数据库中写入内容。
读
在尝试读数据库的时候,从连接UNLOCKED转为SHARED(共享锁),由于共享所可以同时存在,其他连接也可以获取SHARED(共享锁),从而实现读和读的并发。
锁的变化状态:
UNLOCKED -> PENDING -> SHARED -> UNLOCKED
写
一个连接写数据库的时候:
首先由UNLOCKED转换为SHARED(共享锁)
共享锁升级为预留锁,统一时间只能有一个连接处于预留锁状态,这时候Pager初始化回滚日志,用于故障恢复,当B-Tree修改页的时候,这些页都会存储到日志文件里。
事务提交,锁升级为PENDING,此时阻止其他连接获取共享锁,等待已经获取共享锁的连接执行完毕。
升级为EXCLUSIVE,开始实际操作数据库文件
锁状态变化:
UNLOCKED -> SHARED -> RESVERED -> PENDING-> EXCLUSIVE -> UNLOCKED
Sqlite有一个配置是synchronous,这个配置保证了数据从内存中写入到了磁盘,如果配置为OFF,效率提高50倍,但是无法保证持久性。
等待锁
一个SELECT语句在执行的时候,必须获得数据库的共享锁,若此时正好有一个活跃的写操作,那么SELECT语句无法获取共享锁,会返回 SQLITE_BUSY
。可以设置超时时间:
sqlite3_busy_timeout()
死锁
两个连接A和B:
B开始事务,尝试写入,这时候获取保留锁,开始操作Pager。此时A获取共享锁,A尝试写入,尝试转换到保留锁失败,这时候A处于共享状态,等待升级为可写入状态。B commit的时候,因为共享锁的存在,所以无法进入独占锁,导致死锁。
一个语句在遍历表的时候,同时进行写入表,也可能会造成死锁。
事务模式
可以以三种方式开始事务:
begin deferred(延迟) 默认就是这种模式,以这种模式开始的事务一开始不获取任何锁,是处于unlocked状态的。对数据库第一次读的时候,获取共享锁,对数据库第一次写的时候,获取保留锁。
begin immediate。事务开始的时候尝试获取保留锁,获取成功后别的连接就不能写了,但是可以读,commit的时候可能会返回SQLITE_BUSY,这意味着需要等待其他读操作完成。
begin exclusive。事务开始的时候尝试获取独占锁,这样其他连接无法进行读写。
可以用事务模式来解决死锁的问题,例子中的死锁问题,A和B可以用begin immediate来开始事务,这样就不会存在B等待A释放共享锁。
事务冲突
Sqlite提供几种策略来处理
replace 由新的一行来替换有冲突的行
ignore 跳过有冲突的行
fail 到有冲突的行终止命令,但是不恢复之前已经修改的记录。
abort(默认) 终止命令,恢复命令做的修改
rollback(最严格),终止命令和事务,回滚整个事务
WAL
WAL的全称是write ahead log,使用WAL文件能够提高数据库并发性能。
WAL文件替代了回滚日志,它的优点:
大多数情况下,速度有质的提升
更好的并发性能,由于读不回block写,写也不会block读
磁盘I/O操作更序列
使用更少的fsync(),所以在低质量磁盘上更不容易出问题
缺点:
无法改变Page的大小
WAL在读数量远高于写数量的应用中会略慢1%-2%
生成额外的WAL文件
WAL的原理:
对数据库修改是是写入到WAL文件里的,这些写是可以并发的(WAL文件锁)。所以并不会阻塞其语句读原始的数据库文件。当WAL文件到达一定的量级时(CheckPoint),自动把WAL文件的内容写入到数据库文件中。
当一个连接尝试读数据库的时候,首先记录下来当前WAL文件的末尾 end mark)。然后,先尝试WAL文件里查找对应的Page,通过WAL-Index来对查找加速(放在共享内存里),如果找不到再查找数据库文件。
WAL要定期同步到数据库文件里,大的WAL文件会降低读读性能。WAL越小,读性能越好,但是写性能越差,默认是1000个Page。
可以通过sqlite3_wal_checkpoinnt()来强制进行checkpoint。
WAL模式的数据库要求可写权限,因为wal-index文件需要在第一次访问的时候重新生成。
---------------------
作者:黄文臣
原文:https://blog.csdn.net/Hello_Hwc/article/details/79647470
以上所述就是小编给大家介绍的《Sqlite的事务,锁和WAL模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 云设计模式之 : 补偿事务模式
- 分布式事务之事务实现模式与技术(四)
- 分布式事务方案:SAGA 模式
- Seata 0.9.0 发布,支持 saga 事务模式
- Seata 1.2.0 重磅发布,支持 XA 事务模式
- 事务系统实现模式很简单?你确定没忽视这些差异?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据结构算法与应用
塞尼 / 机械工业出版社 / 1999-3 / 49.00元
数据结构、算法与应用—C++语言描述(英文版),ISBN:9787111070177,作者:(美)塞尼 著一起来看看 《数据结构算法与应用》 这本书的介绍吧!