SQLite也可能出现死锁
提到锁就不得不说到死锁的问题,而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也可能出现死锁的更多相关文章
- 《JAVA高并发编程详解》-程序可能出现死锁的场景
- SQLite在多线程环境下的应用
文一 SQLite的FAQ里面已经专门说明,先贴出来.供以后像我目前的入门者学习. (7) 多个应用程序或者同一个应用程序的多个例程能同时存取同一个数据库文件吗? 多进程可以同时打开同一个数据库,也可 ...
- iOS sqlite3数据库解析
看来从版本3.3.1基本上已经支持线程句柄的传递功能.具体限制我标记了一下.(6) Is SQLite threadsafe?SQLite is threadsafe. We make this co ...
- sqlite3 多线程和锁 ,优化插入速度及性能优化
一. 是否支持多线程? SQLite官网上的"Is SQLite threadsafe?"这个问答. 简单来说,从3.3.1版本开始,它就是线程安全的了.而iOS的SQLite ...
- Java:多线程<三>死锁、线程间通讯
死锁: 同步嵌套同步,而且使用的锁不是同一把锁时就可能出现死锁 class Test implements Runnable { private boolean flag; Test(boolean ...
- [翻译]:SQL死锁-阻塞
一般情况下死锁不是一步到位的,它必须满足特定的条件,然后形成资源的循环依赖才会产生死锁,死锁之前一定会出现阻塞,由阻塞升级才有可能出现死锁,所以我们有必要了解系统中都有哪些已经被阻塞的锁. 我在解决共 ...
- java 死锁及解决
Java线程死锁如何避免这一悲剧 Java线程死锁需要如何解决,这个问题一直在我们不断的使用中需要只有不断的关键.不幸的是,使用上锁会带来其他问题.让我们来看一些常见问题以及相应的解决方法: Jav ...
- SQL Server 死锁概念和分析
锁的概念 锁是什么 锁是数据库中在并发操作情形下保护资源的机制.通常(具体要看锁兼容性)只有锁的拥有者才能对被锁的资源进行操作,从而保证数据一致性. 锁的概念可分为几部分 锁资源(锁住什么) 锁模式( ...
- java 线程的死锁问题
以下的情况可能出现死锁 1.一个对象的同步方法去调用另一个对象的同步方法,同时另一个对象的同步方法也在调用这个对象的同步方法,导致一定几率的死锁,不一定每次都会出现死锁,模拟的代码如下 package ...
随机推荐
- Laravel5性能优化技巧
分享一些 Laravel 开发的最佳实践,还有调优技巧,后面陆续整理中 1.配置缓存信息 使用laravel自带的artisan命令,将所有config里面的配置都缓存到一个文件里. php arti ...
- 解决org.hibernate.HibernateException: identifier of an instance of com.ahd.entity.Order was altered from2 to 0
错误信息 严重: Servlet.service() for servlet [springmvc] in context with path [/order] threw exception [Re ...
- python面向对象学习(三)私有属性和私有方法
目录 1. 应用场景和定义方式 2. 伪私有属性和私有方法 在java或者其他的编程语言中,使用访问修饰符来限制属性和方法的访问级别,一般有public.protected.default.priva ...
- 【Linux】nginx常用命令
相关内容链接 Centos之安装Nginx及注意事项 [nginx]详细配置说明 nginx常用命令 [重新加载配置]sudo nginx -s reload [打开nginx配置]sudo vim ...
- javascript html页面中的内容替换
<script language="javascript"> function ffRed(){ var xsxf = document.getElementById ...
- BZOJ2199: [Usaco2011 Jan]奶牛议会(2-SAT)
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 559 Solved: 360[Submit][Status][Discuss] Descriptio ...
- HDU4609 3-idiots(生成函数)
题意 链接 Sol 这个题就很休闲了.. 首先这是个数数题,我们要求的是\(\frac{\sum{[a_i + a_j > a_k]}}{C_n^3}\) 其中\(a\)按从小到大排序, \(i ...
- 2018-10-19 Chrome插件实现GitHub代码离线翻译v0.0.4
续前文Chrome插件实现GitHub代码翻译v0.0.3. 添加了对驼峰命名的支持. 由于调用浏览器插件-离线英汉词典进行词汇翻译, 因此也不依赖于任何在线翻译服务. Chrome插件: 官网链接 ...
- JS里面的装箱和拆箱操作
平日工作里,我想各位少侠对下面的用法都不陌生吧 var s1 = "abc"; var s2 = s1.indexOf("a") 还有例如什么indexOf() ...
- vue.js及项目实战[笔记]— 03 vue.js插件
一. vue补充 1. 获取DOM元素 救命稻草,document.querySelector 在template中标示元素`ref = "xxx" 在要获取的时候,this.$r ...