提到锁就不得不说到死锁的问题,而SQLite也可能出现死锁。
下面举个例子:
连接1:BEGIN (UNLOCKED)
连接1:SELECT ... (SHARED)
连接1:INSERT ... (RESERVED)
连接2:BEGIN (UNLOCKED)
连接2:SELECT ... (SHARED)
连接1:COMMIT (PENDING,尝试获取EXCLUSIVE锁,但还有SHARED锁未释放,返回SQLITE_BUSY)
连接2:INSERT ... (尝试获取RESERVED锁,但已有PENDING锁未释放,返回SQLITE_BUSY)
现在2个连接都在等待对方释放锁,于是就死锁了。当然,实际情况并没那么糟糕,任何一方选择不继续等待,回滚事务就行了。

不过要更好地解决这个问题,就必须更深入地了解事务了。
实际上BEGIN语句可以有3种起始状态:
DEFERRED:默认值,开始事务时不获取任何锁。进行第一次读操作时获取SHARED锁,进行第一次写操作时获取RESERVED锁。
IMMEDIATE:开始事务时获取RESERVED锁。
EXCLUSIVE:开始事务时获取EXCLUSIVE锁。

现在考虑2个事务在开始时都使用IMMEDIATE方式:
连接1:BEGIN IMMEDIATE (RESERVED)
连接1:SELECT ... (RESERVED)
连接1:INSERT ... (RESERVED)
连接2:BEGIN IMMEDIATE (尝试获取RESERVED锁,但已有RESERVED锁未释放,因此事务开始失败,返回SQLITE_BUSY,等待用户重试)
连接1:COMMIT (EXCLUSIVE,写入完成后释放)
连接2:BEGIN IMMEDIATE (RESERVED)
连接2:SELECT ... (RESERVED)
连接2:INSERT ... (RESERVED)
连接2:COMMIT (EXCLUSIVE,写入完成后释放)
这样死锁就被避免了。

而EXCLUSIVE方式则更为严苛,即使其他连接以DEFERRED方式开启事务也不会死锁:
连接1:BEGIN EXCLUSIVE (EXCLUSIVE)
连接1:SELECT ... (EXCLUSIVE)
连接1:INSERT ... (EXCLUSIVE)
连接2:BEGIN (UNLOCKED)
连接2:SELECT ... (尝试获取SHARED锁,但已有EXCLUSIVE锁未释放,返回SQLITE_BUSY,等待用户重试)
连接1:COMMIT (EXCLUSIVE,写入完成后释放)
连接2:SELECT ... (SHARED)
连接2:INSERT ... (RESERVED)
连接2:COMMIT (EXCLUSIVE,写入完成后释放)
不过在并发很高的情况下,直接获取EXCLUSIVE锁的难度比较大;而且为了避免EXCLUSIVE状态长期阻塞其他请求,最好的方式还是让所有写事务都以IMMEDIATE方式开始。
顺带一提,要实现重试的话,可以使用sqlite3_busy_timeout()或sqlite3_busy_handler()函数。

由此可见,要想保证线程安全的话,可以有这4种方式:

  • SQLite使用单线程模式,用一个专门的线程访问数据库。
  • SQLite使用单线程模式,用一个线程队列来访问数据库,队列一次只允许一个线程执行,队列里的线程共用一个数据库连接。
  • SQLite使用多线程模式,每个线程创建自己的数据库连接。
  • SQLite使用串行模式,所有线程共用全局的数据库连接。

作者:Crazy2015
链接:https://www.jianshu.com/p/15051fbd5a35
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

SQLite也可能出现死锁的更多相关文章

  1. 《JAVA高并发编程详解》-程序可能出现死锁的场景

  2. SQLite在多线程环境下的应用

    文一 SQLite的FAQ里面已经专门说明,先贴出来.供以后像我目前的入门者学习. (7) 多个应用程序或者同一个应用程序的多个例程能同时存取同一个数据库文件吗? 多进程可以同时打开同一个数据库,也可 ...

  3. iOS sqlite3数据库解析

    看来从版本3.3.1基本上已经支持线程句柄的传递功能.具体限制我标记了一下.(6) Is SQLite threadsafe?SQLite is threadsafe. We make this co ...

  4. sqlite3 多线程和锁 ,优化插入速度及性能优化

    一. 是否支持多线程?   SQLite官网上的"Is SQLite threadsafe?"这个问答. 简单来说,从3.3.1版本开始,它就是线程安全的了.而iOS的SQLite ...

  5. Java:多线程<三>死锁、线程间通讯

    死锁: 同步嵌套同步,而且使用的锁不是同一把锁时就可能出现死锁 class Test implements Runnable { private boolean flag; Test(boolean ...

  6. [翻译]:SQL死锁-阻塞

    一般情况下死锁不是一步到位的,它必须满足特定的条件,然后形成资源的循环依赖才会产生死锁,死锁之前一定会出现阻塞,由阻塞升级才有可能出现死锁,所以我们有必要了解系统中都有哪些已经被阻塞的锁. 我在解决共 ...

  7. java 死锁及解决

    Java线程死锁如何避免这一悲剧  Java线程死锁需要如何解决,这个问题一直在我们不断的使用中需要只有不断的关键.不幸的是,使用上锁会带来其他问题.让我们来看一些常见问题以及相应的解决方法: Jav ...

  8. SQL Server 死锁概念和分析

    锁的概念 锁是什么 锁是数据库中在并发操作情形下保护资源的机制.通常(具体要看锁兼容性)只有锁的拥有者才能对被锁的资源进行操作,从而保证数据一致性. 锁的概念可分为几部分 锁资源(锁住什么) 锁模式( ...

  9. java 线程的死锁问题

    以下的情况可能出现死锁 1.一个对象的同步方法去调用另一个对象的同步方法,同时另一个对象的同步方法也在调用这个对象的同步方法,导致一定几率的死锁,不一定每次都会出现死锁,模拟的代码如下 package ...

随机推荐

  1. strdup strcpy 的区别

    strdup可以直接把要复制的内容复制给没有初始化的指针,因为它会自动分配空间给目的指针 strcpy的目的指针一定是已经分配内存的指针

  2. JVM内存区域划分Eden Space,Survivor Space,Tenured Gen,Perm Gen

    jvm区域总体分两类,heap区和非heap区.heap区又分:Eden Space(伊甸园).Survivor Space(幸存者区).Tenured Gen(老年代-养老区). 非heap区又分: ...

  3. couldn't resolve host api.weixin.qq.com

    1.代理服务器突然出现 couldn't resolve host api.weixin.qq.com 不知原因 2.重启nginx无效-----代码肯定没有动过(之前出现过,过了一天恢复) 3.防火 ...

  4. HTML5 常用标签整理

    <!--1.  html5 文本 --> <div> <header> <hgroup> <h1>h1</h1> <h2& ...

  5. 用js实现超链接导航菜单点击切换选中时的状态

    项目中使用到点解导航切换不同的颜色,如果只是li选项卡还好办,这次用到的超链接选项卡,因为a链接每次点击都会刷新,所以浏览器记不住点击的状态,也没法切换点击状态,因为项目中有好多地方要用到,在网上找了 ...

  6. springboot 事务管理

    添加注解就完事儿了 @Transactional 1,Propagation  事务的传播行为 Propagation.REQUIRED 如果存在事务,就加入,没有的话就创建(默认值) 比如 A 方法 ...

  7. 基于Python实现的死链接自动化检测工具

    基于Python实现的死链接自动化检测工具   by:授客 QQ:1033553122 测试环境: win7 python 3.3.2 chardet 2.3.0 脚本作用: 检测系统中访问异常(请求 ...

  8. Testlink1.9.17使用方法(第六章 测试计划制定)

    第六章 测试计划制定 QQ交流群:585499566 在TestLink系统中,一个完整的测试计划包括:集成测试阶段.系统测试阶段. 一. 创建测试计划 1,点击主页上[测试计划管理] 2,在“测试计 ...

  9. matlab练习程序(求向量间的旋转矩阵与四元数)

    问题是这样,如果我们知道两个向量v1和v2,计算从v1转到v2的旋转矩阵和四元数,由于旋转矩阵和四元数可以互转,所以我们先计算四元数. 我们可以认为v1绕着向量u旋转θ​角度到v2,u垂直于v1-v2 ...

  10. Scala依赖注入

    控制反转(Inversion of Control,简称IoC),是面向对象编程中的一种设计原则,可以用来降低计算机代码之间的耦合程度.其中最常见的方式叫做依赖注入(Dependency Inject ...