SQLite数据库锁问题

转自:http://blog.csdn.net/rongyongfeikai2/article/details/41311193

记得以前设计评审时,想用SQLite数据库实现某个功能,被教导说应该用Postgresql数据库,因为Postgresql数据库是行锁,而SQLite的锁粒度太粗了。当时还没有什么感觉。

后来在另一个产品的群里面,经常看到其中的开发和测试说SQLite数据库死锁了。这才留了一下心。

最近又要使用它,于是拜读了下《SQLite权威指南》,里面赫赫一句话:SQLite处理并发读没有什么问题,但是如果你的应用需要并发写的话,那么SQLite就不适合你了。

看了一下SQLite数据库的锁机制:

它包括四种锁,共享锁(Shared lock)、预留锁(Reserved lock)和未决锁(Pending lock)、排他锁(Exclusive lock)

其中读操作,用的是Shared lock,所以并发的多个读数据库。如果有一个读操作存在,那么都不会允许写。

而写就比较麻烦,

1.它首先会申请一个预留锁(Reserved lock),在启用Reserved lock之后,已存在的读可以继续读,也可以有新的读请求。

2.然后,它会把需要更新的数据写到缓冲区中。

3.需要写到缓冲区的更新写完以后,就需要将更新刷到硬盘db了。这时,它会申请Pending lock,就不能再有新的Shared lock申请了,也就是阻止了新的读操作。但是已经存在的读操作还是可以继续读的。然后它就等待,直到没有读操作存在(即所有的读都已经结束)这个时候,它就会申请排他锁,此时不允许有其他锁的存在,然后进行commit,将缓冲区的数据写入db中。

书上给举了个例子:

B进行写操作,申请了预留锁;然后A进行读操作,申请了共享锁(有预留锁时,是允许读操作申请的);然后A又同时想进行写操作(未释放共享锁的情况),此时申请预留锁(因为已经有预留锁存在了)失败;B写完缓存,想commit时,申请了未决锁,但是无法从未决锁提升到排他锁(因为有共享锁存在)。此时,发生死锁,A和B都想等待对方释放锁。

对应一下自己的场景:

1.页面有多个读

2.后台会定时写

按照书上说的,写锁的时长大概是几毫秒。我写程序也尽量注意了。也许在极端情况下,在写时,恰好有读锁未释放,不过几毫秒内,概率不算很大。

另外,就算是这种极端情况未写成功,在下一个5分钟写时,也会把上一个5分钟未commit的给补救上去。从前台看来,就是数据会有一定时延。

另外一个隐含的需求:页面可能也需要进行更新数据的操作,这个写是有用户的某个动作触发的,那么在多用户的情况下,读写同时、写写同时的概率就会很大。对此,希望是采取规避的方式,在后台提供与此更新操作的脚本,而非在前台页面提供。

由此可见,SQLite作为一个嵌入式数据库,不太适合用在高并发的场景下;另外,以上都是理论,希望有时间阅读源码,能够彻底弄清楚一切。

讨论了下,为了规避风险,还是不用SQLite了。什么时候,SQLite才能把数据库级别的锁改为行锁?不过如果真的SQLite支持行锁,那么就违背它轻量、简单的初衷了。所以,这个终究是一个梦。

    原文作者:java锁
    原文地址: https://blog.csdn.net/fuxingdaima/article/details/52948236
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞