iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Android SQLite3多线程操作问题研究总结
  • 228
分享到

Android SQLite3多线程操作问题研究总结

sqlite3多线程SQLite线程Android 2022-06-06 10:06:14 228人浏览 薄情痞子
摘要

最近做项目时在多线程读写数据库时抛出了异常,这自然是我对sqlite3有理解不到位的地方,所以事后仔细探究了一番。 1.关于getWriteableDataBase()和get

最近做项目时在多线程读写数据库时抛出了异常,这自然是我对sqlite3有理解不到位的地方,所以事后仔细探究了一番。

1.关于getWriteableDataBase()和getReadableDatabase()的真正作用
getWriteableDataBase()其实是相当于getReadableDatabase()的一个子方法,getWriteableDataBase()是只能返回一个以读写方式打开的SQLiteDatabase的引用,如果此时数据库不可写时就会抛出异常,比如数据库的磁盘空间满了的情况。而getReadableDatabase()一般默认是调用getWriteableDataBase()方法,如果数据库不可写时就会返回一个以只读方式打开的SQLiteDatabase的引用,这就是二者最明显的区别。

关键源码如下:


public synchronized SQLiteDatabase getWritableDatabase() {
  if (mDatabase != null) {
    if (!mDatabase.isOpen()) {
    // darn! the user closed the database by calling mDatabase.close()
    mDatabase = null;
    } else if (!mDatabase.isReadOnly()) {
    return mDatabase; // The database is already open for business
    }
  }
... ...
public synchronized SQLiteDatabase getReadableDatabase() {
  if (mDatabase != null) {
    if (!mDatabase.isOpen()) {
    // darn! the user closed the database by calling mDatabase.close()
    mDatabase = null;
    } else {
    return mDatabase; // The database is already open for business
    }
  }
 ... ...
  try {
    return getWritableDatabase();
  }
... ...

2.SQLiteDatabase的同步锁

其实在只使用一个SQLiteDatabase的引用时,SQLiteDatabase对CRUD操作都会加上一个(因为是db文件,所以精确至数据库级),这就保证了在同一时间你只能进行一项操作,无论是不是在同一个线程中,这就导致了如果你在程序中对SQLiteOpenHelper使用了单例模式,那么你对数据库读写进行任何的优化操作都是"徒劳"。

3.多线程读数据库

仔细看源码你会发现,在数据库操作中只有add,delete,update会调用lock(),而query()是不会调用的,但是在加载数据时,调用了SQLiteQuery的fillWindow方法,而该方法依然会调用SQLiteDatabase.lock(),所以要想真正的实现多线程读数据库,只能每个线程使用各自的SQLiteOpenHelper对象进行读操作,这样就可避开同步锁。关键源码如下:


 int fillWindow(CursorWindow window,
  int maxRead, int lastPos) {
  long timeStart = SystemClock.uptimeMillis();
  mDatabase.lock();
  mDatabase.logTimeStat(mSql, timeStart, SQLiteDatabase.GET_LOCK_LOG_PREFIX);
  try {... ...

4.多线程读写

实现多线程读写的关键是enableWriteAheadLogging属性,这个方法 api Level 11添加的,也就是所3.0以上的版本就基本不可能实现真正的多线程读写了。简单的说通过调用enableWriteAheadLogging()和disableWriteAheadLogging()可以控制该数据是否被运行多线程读写,如果允许,它将允许一个写线程与多个读线程同时在一个SQLiteDatabase上起作用。实现原理是写操作其实是在一个单独的log文件,读操作读的是原数据文件,是写操作开始之前的内容,从而互不影响。当写操作结束后读操作将察觉到新数据库的状态。当然这样做的弊端是将消耗更多的内存空间。

5.多线程写

这个就不用多想了,SQLite压根不支持,如果实在有需求可以使用多个数据库文件。

6.备注

(1)你有没有想SQLite最多支持多少个数据库连接,其实在官方API文档(enableWriteAheadLogging ()方法)中给出了最精确的答案:The maximum number of connections used to execute queries in parallel is dependent upon the device memory and possibly other properties.就是看你有多少内存,但是我感觉这话说的有点大,是不?哈哈。

(2)当你在多线程中只使用一个SQLiteDatabase的引用时,需要格外注意你SQLiteDataBase.close()调用的时机,因为你是使用的同一个引用,比如在一个线程中当一个Add操作结束后立刻关闭了数据库连接,而另一个现场中正准备执行查询操作,但此时db已经被关闭了,然后就会报异常错误。此时一般有三种解决方案,①简单粗暴给所有的CRUD添加一个 synchronized关键字;②永远不关闭数据库连接,只在最后退出是关闭连接。其实每次执行getWriteableDataBase()或getReadableDatabase()方法时,如果有已经建立的数据库连接则直接返回(例外:如果旧的连接是以只读方式打开的,则会在新建连接成功的前提下,关闭旧连接),所以程序中将始终保持有且只有一个数据库连接(前提是单例),资源消耗的很少。③可以自己进行引用计数,简单示例代码如下:


//打开数据库方法
public synchronized SQLiteDatabase openDatabase() {
if (mOpenCounter.incrementAndGet() == 1) {
 // Opening new database
 try {
 mDatabase = sInstance.getWritableDatabase();
 } catch (Exception e) {
 mDatabase = sInstance.getReadableDatabase();
 }
 }
return mDatabase;
}
//关闭数据库方法
public synchronized void closeDatabase() {
 if (mOpenCounter.decrementAndGet() == 0) {
 // Closing database
 mDatabase.close();
 }
 }

 (3)还有一些比较好的习惯和常识,例如关闭Cursor,使用Transaction,SQLite存储数据时其实不区分类型,以及SQLite支持大部分标准SQL语句,增删改查语句都是通用的等等。

您可能感兴趣的文章:Android开发教程之handle实现多线程和异步处理Android多线程及异步处理问题详细探讨Handler与Android多线程详解android中多线程下载实例Android中创建多线程管理器实例android 多线程技术应用Android开发笔记之:深入理解多线程AsyncTaskAndroid多线程处理机制中的Handler使用介绍Android 中 EventBus 的使用之多线程事件处理Android实现多线程下载文件的方法Android多线程学习实例详解


--结束END--

本文标题: Android SQLite3多线程操作问题研究总结

本文链接: https://www.lsjlt.com/news/26864.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作