Sqlite的事务,锁和WAL模式
前言事务定义了一组SQL语句的边界,这组SQL语句要么都执行,要么都不执行,事务保证了数据库完整性中的原子性。事务与数据库锁是紧密相关的,Sqlite用锁来保证事务的并发和执行顺序。 事务在讲解事务的原理之前,我们先看看事务相关的API,主要有三个:
我们首先来看看回滚,假设有这样的一个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;
多链接模型常见的模型:一个数据库文件,多个连接,每个连接有自己的语句。 一些名词的解释:
在写文件的时候,无法避免的要锁数据库文件,锁数据库文件后,其他连接就无法读/写数据库。事务这种延迟和批量写入的方式,能够最大限度的提高数据库的并发性能。 当两个连接同时操作数据库进行读写的时候,SQLITE如何保证事务的正确性,以及如何保证读和读是可以并发的呢?答案是不同优先级的锁。 锁大多数时候,锁的持续时间和事务是一样的,虽然并不是同时开始,但是总是一起结束。 Sqlite采用粗粒度的锁。当一个连接尝试写数据库的时候,所有其他连接都被锁住,直到写连接结束它的事务。Sqlite有一个加锁表,用来帮助不同的写数据库都能在最后一刻加锁。 状态:
读在尝试读数据库的时候,从连接UNLOCKED转为SHARED(共享锁),由于共享所可以同时存在,其他连接也可以获取SHARED(共享锁),从而实现读和读的并发。 锁的变化状态: UNLOCKED -> PENDING -> SHARED -> UNLOCKED 写一个连接写数据库的时候:
锁状态变化: UNLOCKED -> SHARED -> RESVERED -> PENDING-> EXCLUSIVE -> UNLOCKED
等待锁一个SELECT语句在执行的时候,必须获得数据库的共享锁,若此时正好有一个活跃的写操作,那么SELECT语句无法获取共享锁,会返回 sqlite3_busy_timeout()
死锁两个连接A和B: B开始事务,尝试写入,这时候获取保留锁,开始操作Pager。此时A获取共享锁,A尝试写入,尝试转换到保留锁失败,这时候A处于共享状态,等待升级为可写入状态。B commit的时候,因为共享锁的存在,所以无法进入独占锁,导致死锁。 事务模式可以以三种方式开始事务:
事务冲突Sqlite提供几种策略来处理
WALWAL的全称是write ahead log,使用WAL文件能够提高数据库并发性能。 WAL文件替代了回滚日志,它的优点:
缺点:
WAL的原理: 对数据库修改是是写入到WAL文件里的,这些写是可以并发的(WAL文件锁)。所以并不会阻塞其语句读原始的数据库文件。当WAL文件到达一定的量级时(CheckPoint),自动把WAL文件的内容写入到数据库文件中。 当一个连接尝试读数据库的时候,首先记录下来当前WAL文件的末尾 end mark)。然后,先尝试WAL文件里查找对应的Page,通过WAL-Index来对查找加速(放在共享内存里),如果找不到再查找数据库文件。 WAL要定期同步到数据库文件里,大的WAL文件会降低读读性能。WAL越小,读性能越好,但是写性能越差,默认是1000个Page。 可以通过 WAL模式的数据库要求可写权限,因为wal-index文件需要在第一次访问的时候重新生成。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |