sqlite的锁和事务

上一篇 / 下一篇  2016-07-13 16:15:19 / 个人分类:sqlite

测试过程中,需要模拟sqlite数据库锁定的场景用于重现bug和确认修复情况,所以有时间去熟悉了下sqlite的锁和事务的相关内容:

事务的概念:
对事务最初的浅理解就是原子操作,执行或者回滚。
查了下事务的正规概念:事务定义了一组SQL命令的边界,这组命令或者作为一个整体被全部执行,或者都不执行。事务的典型实例是转帐。

事务的3个控制命令:
BEGIN:开始一个事务,之后的所有操作都可以取消
COMMIT:使BEGIN后的所有命令得到确认
ROLLBACK:还原BEGIN之后的所有操作

eg: 
sqlite> select count(*) from newboxlist; 
1876
sqlite> begin; 
sqlite> delete from newboxlist; 
sqlite> rollback; 
sqlite> select count(*) from newboxlist; 
1876

上面开始了一个事务,先删除了newboxlist表的所有行,但是又用ROLLBACK进行了回卷。再执行SELECT时发现表中没发生任何改变。

注:
SQLite默认情况下,每条SQL语句自成事务(自动提交模式)。

在SQLite中,锁和事务是紧密关联的。所以了解一些关于锁的内容:
SQLite采用粗放型的锁。当一个连接要写数据库,所有其它的连接被锁住,直到写连接结束了它的事务。SQLite有一个加锁表,来帮助不同的写数据库都能够在最后一刻再加锁,以保证最大的并发性。
SQLite使用锁逐步上升机制,为了写数据库,连接需要逐级地获得排它锁。

SQLite有5个不同的锁状态:
未加锁(UNLOCKED)
共享 (SHARED)
保留(RESERVED)
未决(PENDING)
排它(EXCLUSIVE)。

每个数据库连接在同一时刻只能处于其中一个状态。每 种状态(未加锁状态除外)都有一种锁与之对应。
最初的状态是未加锁状态,在此状态下,连接还没有存取数据库。当连接到了一个数据库,甚至已经用BEGIN开始了一个事务时,连接都还处于未加锁状态。
未加锁状态的下一个状态是共享状态。为了能够从数据库中读(不写)数据,连接必须首先进入共享状态,也就是说首先要获得一个共享锁。多个连接可以 同时获得并保持共享锁,也就是说多个连接可以同时从同一个数据库中读数据。但哪怕只有一个共享锁还没有释放,也不允许任何连接写数据库。
如果一个连接想要写数据库,它必须首先获得一个保留锁。一个数据库上同时只能有一个保留锁。保留锁可以与共享锁共存,保留锁是写数据库的第1阶段。保留锁即不阻止其它拥有共享锁的连接继续读数据库,也不阻止其它连接获得新的共享锁。
一旦一个连接获得了保留锁,它就可以开始处理数据库修改操作了,尽管这些修改只能在缓冲区中进行,而不是实际地写到磁盘。对读出内容所做的修改保存在内存缓冲区中。
当连接想要提交修改(或事务)时,需要将保留锁提升为排它锁。为了得到排它锁,还必须首先将保留锁提升为未决锁。获得未决锁之后,其它连接就不能 再获得新的共享锁了,但已经拥有共享锁的连接仍然可以继续正常读数据库。此时,拥有未决锁的连接等待其它拥有共享锁的连接完成工作并释放其共享锁。
一旦所有其它共享锁都被释放,拥有未决锁的连接就可以将其锁提升至排它锁,此时就可以自由地对数据库进行修改了。所有以前对缓冲区所做的修改都会被写到数据库文件。

eg:
sqlite> begin; ---这时候依然处于UNLOCKED状态
sqlite> delete from newboxlist; ---这时候处于RESERVED状态

使用lsof来查看数据库文件的连接情况:
[root@mx 0]# lsof /root/all_boxdb
COMMAND   PID USER   FD   TYPE DEVICE    SIZE    NODE NAME
sqlite3 29804 root    3ur  REG   8,17 1047552 2130249 /root/all_boxdb

也可以使用另外开启一个连接,执行事务命令验证:
sqlite> begin;
sqlite> delete from newboxlist;
Error: database is locked---提示已经被锁定




TAG:

 

评分:0

我来说两句

Open Toolbar