关于手表网站建设策划书,网站建设上传和下载,广告设计app哪个好用,西地那非片有依赖性吗概述 SQLite虽然是一个轻量的嵌入式数据库#xff0c;但这并不影响它支持事务。所谓支持事务#xff0c;即需要在并发环境下#xff0c;保持事务的ACID特性。事务的原子性#xff0c;隔离性都需要通过并发控制来保证。那么Sqlite的并发控制是怎样的#xff0c;如何实现但这并不影响它支持事务。所谓支持事务即需要在并发环境下保持事务的ACID特性。事务的原子性隔离性都需要通过并发控制来保证。那么Sqlite的并发控制是怎样的如何实现在这里跟大家分享下我的理解。 SQLite是一个文件数据库所有的数据都在一个db文件中对于wal模式还包含wal索引文件和wal日志文件。SQlite支持库级并发即允许多个读事务同时运行同一时刻最多只有一个写事务读写冲突相对于传统的DBMS支持表级行级甚至MVCCSQLite的库级并发确实显得比较寒碜。但是锁粒度越细意味着维护锁的成本越高系统也会越复杂因此SQLite的封锁机制要简单很多对资源的消耗也非常少。SQLite 3.7版本后对并发控制做了优化推出了WAL日志模式可以实现读写并发但同一个时刻仍然只能有一个写事务。由于SQLite的实现方式SQLite只支持两种隔离级别串行化和读未提交。读未提交就是读全程不上锁串行化在事务开启时上读锁上锁和释放锁同样遵守两阶段锁协议在事务提交或回滚时才释放锁。 文件锁 要说清楚SQLite锁实现机制首先要了解文件锁因为SQLite所有锁实现都是基于文件锁。对于Linux系统文件锁主要包含两类协同锁和强制锁协同锁类似于互斥量需要参与者都遵守游戏规则在操作文件前都先上锁而强制锁由OS内核强制实行。协同锁根据锁粒度分为文件级别和范围级别。锁文件是最简单的对文件加锁的方法每个需要加锁的数据文件都有一个锁文件lock file。当锁文件存在时就认为该数据文件已经被加锁别的进程不应该访问。当锁不存在进程就可以创建一个锁文件然后访问相应的数据文件。只要创建锁的过程是原子的就能保证某一时刻只有一个进程拥有该锁这种方法保证某一时刻只有一个进程访问文件。文件锁的弊端显而易见并发粒度太低。范围锁相对于文件锁可以锁文件的一部分内容并且有读锁和写锁。对于同一部分内容读锁可以共存读锁和写锁互斥。POSIX标准提供接口fcntl()来实现。 锁类型 SQLite中的锁正是利用了范围锁来实现并发控制的目的。SQLite中主要包含了4种锁共享锁(SHARED_LOCK)、保留锁(RESERVED_LOCK)、未决锁(PENDING_LOCK)和排它锁(EXCLUSIVE_LOCK)这4种锁定义了3个区域其中共享锁和排它锁占用文件相同的区域。具体而言SQLite定义了文件的以下区域为锁文件区域由于fcntl可以对不存在的文件区域加锁因此 PENDING_BYTE定位在区域1G的地方即使DB文件没这么大也不影响。三种类型的锁分别在1G1G11G2的偏移处之所以SHARED_SIZE长度是510原因在于windows环境下LockFile()加锁区域不能重叠(Linux没有这种问题)对于同一个字节上锁会影响并发因此设置了一个范围对SHARED_FIRST—SHARED_FIRST SHARED_SIZE范围内的随机数进行加锁这样可以减少冲突保证高效的读取文件。具体锁类别和说明参见表1 锁类别 字节范围 说明 PENDING_BYTE 0x40000000 一种过渡锁读事务获取读锁写事务获取写锁前都需要获取该锁。 RESERVED_BYTE 0x40000001 表示线程要开始写操作某一时刻只能有一个RESERVED Lock但是RESERVED锁和SHARED锁可以共存而且可以对数据库加新的SHARED锁。 SHARED_LOCK 0x40000002-0x40000200 共享锁开启事务时都需要获取该锁 EXCLUSIVE_LOCK 0x40000002-0x40000200 排它锁 表1 从各个锁的作用来看不免会疑问为啥要加上RESERVED_LOCK和PENDING_LOCK两种类型直接通过共享锁和排它锁不就可以达到读读共享读写互斥的目的了吗。这里引入这Reserved锁的目的是为了提高并发。由于SQLite只有库级排斥锁EXCLUSIVE LOCK如果写事务一开始就上EXCLUSIVE锁然后再进行实际的数据更新写磁盘操作这会使得并发性大大降低。而SQLite一旦得到数据库的RESERVED锁就可以对缓存中的数据进行修改而与此同时其它进程可以继续进行读操作。直到真正需要写磁盘时才对数据库加EXCLUSIVE锁。Pending锁的作用主要是为了防止写饿死的情况写事务获取Pending锁后新的读事务无法再进来然后再加EXCLUSIVE锁这样写事务获取锁的几率大大提高读写事务的流程如下表2状态变迁图如图1。 类型 操作 锁信息 说明 读事务 begin 不持有锁 select c1 from user where id1 Lock: Pending(Read) Lock:Shared(Read) Unlock:Pending 获取Shared读锁前需要先获取Pending共享锁 通过这种方式与写事务互斥。 commit UnLock:Shared 写事务 begin Update c1c11 where id1 Lock: Pending(Read) Lock:Shared Unlock:Pending Lock:Reserved(Write) 先获取Shared读锁然后获取Reserved的排它锁阻止其它写事务 commit Lock:Pending(Write) Lock:Exclusive(Write) Unlock: Pending Unlock: Exclusive(Write) 获取Pending的排它锁阻止新的读事务最后上排它锁阻止所有读事务读写不能并发 Pending锁方式好处是减少写饿死的几率。 表2 图1 Wal锁类型 引入WAL机制后SQLite开始支持读写并发并且引入了WAL日志文件锁。WAL日志锁实质是锁wal-index文件的区域根据不同的锁类型将wal-index文件的不同区域划定义成不同的锁主要有读锁写锁检查点锁具体如表34。WAL模式下最新的数据位于日志文件中无论是读事务还是写事务都需要持有WAL_READ_LOCK的读锁因为它们都需要获取最新的事务点。因此做检查点时可以通过对WAL_READ_LOCK位置(124-127)上锁来确定检查点需要等待还是停止推进。同时我们也可以看到对于DB文件读写事务都只需要对DB文件上读锁对于WAL日志文件WAL_READ_LOCK和WAL_WRITE_LOCK位于不同的位置读写相互不影响所以读写不互斥。 锁类别 字节范围 说明 读事务(WAL) begin select c1 from user where id1 DB文件 Lock: Pending(Read) Lock:Shared Unlock:Pending WAL文件 LockWAL_READ_LOCK(Read) 除了获取DB文件锁还需要获取WAL锁得到最新提交事务的位点。 若有事务再作检查点需要重试多次。 commit UnlockWAL_READ_LOCK UnlockShared 写事务(WAL) begin Update c1c11 where id1 DB文件 Lock: Pending-Read Lock:Shared(Read) Unlock:Pending WAL文件 LockWAL_READ_LOCK(Read) LockWAL_WRITE_LOCK(Write) 通过 EXCLUSIVE-WRITE-LOCK控制写写并发 由于不操作DB文件因此不存在读写冲突读写可以并发。 commit WAL文件 LockSHARED-READ-LOCK UnlockWAL_READ_LOCK(Read) Unlock WAL_WRITE_LOCK(Write) DB文件 UnlockShared 获取SHARED-READ-LOCK目的是为了获取最新提交日志的位点 检查点 操作 (WAL) WAL文件 LockWAL_CKPT_LOCK(write) LockWAL_READ_LOCK(write) UnLockWAL_READ_LOCK UnLockWAL_CKPT_LOCK EXCLUSIVE-CKPT-LOCK 保证只有一个写事务做检查点 WAL_READ_LOCK阻止读写事务。 表3 锁类别 字节范围 说明 WAL_WRITE_LOCK 120 写锁位置 WAL_CKPT_LOCK 121 检查点锁位置 WAL_RECOVER_LOCK 122 故障恢复锁位置 WAL_READ_LOCK 123 读锁(表示不需要wal文件) 124-127 读锁(每个位置对应一个锁) 做检查点时逐一对每个位置上写锁若上锁失败表示对应位置上的读事务没有结束根据检查点策略确定是等待(FULL)还是停止推进(PASSIVE)。 表4 调试 SQLite通过几个宏定义可以打印语句执行的锁信息方便大家了解语句执行中加了哪些锁什么时候加的什么时候释放的以及如何处理锁冲突。具体的宏包括SQLITE_LOCK_TRACESQLITE_FORCE_OS_TRACE和SQLITE_DEBUG具体可以在代码中查看宏定义的注释。 gcc sqlite3.c -g -lpthread -ldl -fPIC -shared -DSQLITE_TEST -DSQLITE_DEBUG -DSQLITE_LOCK_TRACE -DSQLITE_FORCE_OS_TRACE -o libsqlite3.so 参考文档 http://my.oschina.net/u/587236/blog/129022 http://www.cnblogs.com/hustcat/archive/2009/03/01/1400757.html 转载于:https://www.cnblogs.com/cchust/p/4761814.html