sqlite数据库并发问题

 

 

目录

描述

sqlite的锁

死锁现象

解决方法


描述

做过一些qt工程项目,单机版软件中经常性的会使用sqlite数据库,优缺点都很明显。

优点:轻量级,容易跨平台移植,操作简单,尤其针对linux这种种类繁杂的系统,适配起来相对简单,而且一些系统已经内置了sqlite动态库。

缺点:既然是轻量级,那功能和性能上就有点跟不上了,尤其是多线程操作时的并发问题。


sqlite的锁

用过sqlite的小伙伴都知道,sqlite使用的是库锁,当然也可以理解成“文件锁”。sqlite的锁并非单纯的互斥,多线程环境下使用不当就容易陷入死锁。

sqlite的锁有shared共享锁、reserve预留锁、exclusive独占锁/排他锁、pending未决锁 等几种。

  1. 当进行select时候获取的是shared,多个读操作同时可以获取shared锁。
  2. 当进行update、delete、drop的时候获取的是reserve,reserve与shared不互斥,两个reserve不能同时获取。
  3. 当进行commit事务提交的时候,获取的是exclusive,exclusive与其他锁不能同时获取。
  4. pending是防止写饿死存在的,可以理解为获取exclusive之前获取的一种锁。假如没有pending,当读操作频繁时,不间断的shared锁出现,exclusive的特性使得exclusive获取不到,就出现了写饿死现象。所以commit事务的时候先获取pending锁,当shared存在时,依然可以获取pending锁,两个pending不能同时获取,而且获取pending之后,新的shared则不能再获取。

死锁现象

以两个线程同时操作数据库举个例子:

pthreadA创建了数据库连接,执行select查询获取了shared锁。

pthreadB创建了数据库连接,执行了update更新并获取了reserve锁。

pthreadA也打算执行delete操作(需要获取reserve锁),reserve锁被pthreadB占用了,无法正常执行。

pthreadB更新完成,进行commit提交的时候需要获取exclusive锁,此时pthreadA占用着数据库的shared锁,无法正常执行。

pthreadA和pthreadB就陷入了死锁的爱恨纠葛。

在上述例子程序中,pthreadA占用着shared锁才导致了死锁的存在,其实如果pthreadA释放了shared锁就不会出现这个问题了。

我们来讨论一下sqlite锁释放的时机:

1、事务结束的时候

2、有next或者step等涉及游标操作的时候,当查询彻底执行完成(游标释放)的时候。

3、如果没有用到事务的话,当一条完整的sql语句执行结束的时候。

4、数据库连接关闭的时候。


解决方法

其实解决死锁的问题也简单,最彻底安全的方式就是进行读写分离,最好是所有写操作交给一个任务线程去搞,读操作就没什么必要了。

如果不考虑性能的话,当然也可以在所有操作数据库的地方加上系统的读写锁或者互斥锁。

当然了,如果不想重整架构,又或者在一些类似界面程序的少量数据的操作中,没有使用到事务或者少量使用事务的话,就注意在一个事务中不要同时出现又读又写的情况。在查询中,有用到游标类的操作,在查询遍历的过程中不要进行修改、删除等操作。抛开事务和游标等操作,正常的sql语句并发执行,其实是不会出现死锁现象的。

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值