Android数据库锁机制

今天介绍下Android数据库锁机制、性能优化的点,之前去面试的时候面试官问我能同时在同个数据库里写两个记录么,对两个不同的表写数据可以么?我知道肯定是不行的,但说不出个所以然,只能浅显地说数据库整体是一个文件,保证并发性的话不能同时对一个文件做写操作哈。那接下来主要会对SQL锁机制做个介绍。


  • 性能优化
  • 锁机制

1.性能优化

1.1数据库insert、query、update、delete的API与execSQL、rawQuery函数执行插入、查询、更新、删除语句操作花费时间的对比。
(1)批量执行1000条,则SqliteDatabase提供的insert、query、update、delete函数和直接execSQL、rawQuery函数的效率差不多。
(2)批量执行10w条,SqliteDatabase提供的insert、query、update、delete函数相对效率比较低。execSQL省去了拼接sql语句的步骤,当数据库越大,差别就越大。
1.2批量操作效率
在数据库中插入大量数据,如果使用遍历insert操作会导致应用响应缓慢,每一次insert操作都会开启一个事务,这样都会执行一次磁盘操作。我们可以通过显示添加事务来提高效率

 db.beginTransaction();
 try {
  for(int i = 0; i < 10000; i++) {
    insert(db, c);
  }
  db.setTransactionSuccessful();
 } catch(Exception ex) {
 } finally {
   db.endTransaction();
 }

这样会将全部要执行的sql语句先缓存在内存当中,然后等到Commit的时候一次性写入数据库,保证数据库文件只被打开关闭了一次。

2.锁机制

SQLite是基于锁来实现并发控制的,SQLite的锁是粗粒度的,所以是轻量级的,当一个连接要写数据库时,所有其他的连接都被锁住,直到写连接结束它的事务。
2.1锁的状态
SQLite数据库连接有5种状态

image.png

未加锁:
未和数据库建立连接、已建立连接但还没访问数据库、已用BEGIN开始了一个事务但未开始读写数据库,处于这些情形时是未加锁状态。
共享锁:
连接需要从数据库中读取数据时,需要申请获得一个共享锁,如果获取成功,则进入共享状态。
预留锁:
连接需要写数据至数据库时,首先申请一个预留锁,一个数据库同时只能有一个预留锁,预留锁可以与共享锁共存。获得预留锁后会进入预留状态,这时会先在缓存区中进行写操作,操作后的结果依然保存在缓存区中,未真正写入数据库。
未决锁:
连接从预留升级为排它前,需要先升级为未决锁,这时其他的连接就不能获取到共享锁了,但已经拥有共享锁的连接仍然正常读数据库,此时,拥有未决锁的连接等待其他拥有共享锁连接完成工作并释放其共享锁后,才能提升到排它锁。
排它锁:
连接需要提交修改时,需要将预留锁升级为排它锁,这时候其他链接都无法获取任何锁,直到当前连接的排它状态结束。
一个连接读数据库的流程如下:
image.png

一个连接写数据库的流程如下:

image.png

但在实际中可能会出现死锁的问题,例如在使用事务的情况下。

image.png

执行顺序1:连接A获取一个未加锁
执行顺序2:连接B获取一个未加锁
执行顺序3:连接B要执行写操作,获得预留锁(数据库连接只能一次有一个预留锁)
执行顺序4:连接A要执行读操作,获取共享锁
执行顺序5:连接B要升级为排它锁前,在执行提交数据库的操作前,先升级成未决锁(这时候不能有新的共享锁了)
执行顺序6:连接B要升级为排它锁,但可能存在4的操作耗时久,共享锁未被释放,连接B需等待
执行顺序7:连接A要执行写操作,需要获取预留锁
执行顺序8:连接A获取预留锁失败,必须先等连接B释放未决锁
于是连接A和连接B相互等待对方,发生死锁。

那么,如何避免这种死锁情况呢?就要谈谈事务类型了。
2.2事务类型
DEFERRED
不获取任何锁,这种是正常执行流程从上往下的,但对数据库进行连接时它本身是不会获取任何锁的,当对数据库进行读操作时,会获取共享锁,当对写操作时,会获取预留锁。
IMMEDIATE
在BEGIN时事务会尝试获取预留锁。如果获取成功,能保证没有其他可以对数据库可以进行写操作,但可以进行读操作。通俗而言就是当前事务在没有结束之前,任何其他线程或进程都无法对数据库进行写操作。
EXCLUSIVE
事务会尝试获取排它锁。一旦获取成功,保证没有额外的连接,这样就能保证对数据库进行读写操作。通俗而言就是当前事务在没有结束之前,任何其他线程或进程都无法对数据库进行读写操作。
其实上面死锁的情况主要是由于一个共享锁未释放导致两个连接互相等待对方。那么如果两个连接都是以IMMEDIATE的方式开启事务的话,那么当下只能有一个连接获取预留锁,其他的连接就得等它操作完。
可能说的有点悬乎,那么我们看下安卓开启事务的代码。

image.png

beginTransaction():使用EXCLUSIVE这种方式的。
beginTransactionNonExclusive():使用IMMEDIATE这种方式的。
具体内部逻辑如下:
image.png

所以说默认情况下使用事务时,只允许一个连接进行数据库读写,这样保证了并发性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,408评论 4 371
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,690评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,036评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,726评论 0 221
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,123评论 3 296
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,037评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,178评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,964评论 0 213
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,703评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,863评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,333评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,658评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,374评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,195评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,988评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,167评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,970评论 2 279

推荐阅读更多精彩内容