首页 > 编程知识 正文

数据库加锁的方法,数据库锁的特点

时间:2023-05-06 10:28:17 阅读:31720 作者:890

今天我们来介绍安卓数据库的锁定机制、性能优化要点。 以前去面试的时候,面试官问我可以在同一个数据库里同时写两个记录吗,可以在两个不同的表上写数据吗? 我知道绝对不行,但我什么也说不出来。 简单地说,整个数据库是一个文件,不能在保证同时性的同时对一个文件进行写入操作。 那么,接下来主要介绍SQL锁定机制。

性能优化

锁定机制

1 .性能优化

1.1比较数据库insert、query、update和delete的API与execSQL和rawQuery函数执行语句插入、查询、更新和删除操作所需的时间。

)1)批量运行1000个时,SQLite数据库提供的insert、query、update、delete函数和直接execSQL、rawQuery函数的效率几乎相同。

)2)批量运行10w条,SQLite数据库提供的insert、query、update、delete函数相对低效。 在execsql中,可以省去连接SQL语句的步骤,数据库越大,差别就越大。

1.2批量操作效率

在数据库中插入大量数据。 使用遍历插入操作时,APP应用程序的响应速度较慢,每个插入操作都会打开一个事务,并执行一次磁盘操作。 可以通过查看附加事务来提高效率

db.beginTransaction (;

try {

for(intI=0; i 10000; I ) {

插入(db,c );

}

db.setTransactionSuccessful (;

}catch(exceptionex ) {

} finally {

db.endTransaction (;

}

这将确保要执行的所有sql语句都缓存在内存中,一次写入数据库,直到发生Commit,并确保数据库文件只打开和关闭一次。

2 .锁定机制

SQLite基于锁定实现并发控制。 SQLite锁定是轻量级的,因为它的粒度很粗,当一个连接写入数据库时,所有其他连接都会被锁定,直到写入连接终止事务。

2.1锁定状态

SQLite数据库连接有五种状态

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事务类型

已延迟

不获取锁定。 这是从正常运行过程的顶部到底部,但连接到数据库时,它本身不获取锁定。 对数据库进行读取操作时获取共享锁定,进行写入操作时获取保留锁定。

信息媒体

事务在BEGIN时尝试获取保留锁。 如果成功,则可以确保没有其他写入数据库

进行读操作。通俗而言就是当前事务在没有结束之前,任何其他线程或进程都无法对数据库进行写操作。

EXCLUSIVE

事务会尝试获取排它锁。一旦获取成功,保证没有额外的连接,这样就能保证对数据库进行读写操作。通俗而言就是当前事务在没有结束之前,任何其他线程或进程都无法对数据库进行读写操作。

其实上面死锁的情况主要是由于一个共享锁未释放导致两个连接互相等待对方。那么如果两个连接都是以IMMEDIATE的方式开启事务的话,那么当下只能有一个连接获取预留锁,其他的连接就得等它操作完。

可能说的有点悬乎,那么我们看下安卓开启事务的代码。

image.png

beginTransaction():使用EXCLUSIVE这种方式的。

beginTransactionNonExclusive():使用IMMEDIATE这种方式的。

具体内部逻辑如下:

image.png

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

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。