探究Android SQLite3多线程
最近做项目时在多线程读写数据库时抛出了异常,这自然是我对SQlite3有理解不到位的地方,所以事后仔细探究了一番。
关于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();
}
... ...
SQLiteDatabase的同步锁
其实在只使用一个SQLiteDatabase的引用时,SQLiteDatabase对CRUD操作都会加上一个锁(因为是db文件,所以精确至数据库级),这就保证了在同一时间你只能进行一项操作,无论是不是在同一个线程中,这就导致了如果你在程序中对SQLiteOpenHelper使用了单例模式,那么你对数据库读写进行任何的优化操作都是"徒劳"。多线程读数据库
仔细看源码你会发现,在数据库操作中只有add,delete,update会调用lock(),而query()是不会调用的,但是在加载数据时,调用了SQLiteQuery的fillWindow方法,而该方法依然会调用SQLiteDatabase.lock(),所以要想真正的实现多线程读数据库,只能每个线程使用各自的SQLiteOpenHelper对象进行读操作,这样就可避开同步锁。关键源码如下:/* package */ int fillWindow(CursorWindow window,
int maxRead, int lastPos) {
long timeStart = SystemClock.uptimeMillis();
mDatabase.lock();
mDatabase.logTimeStat(mSql, timeStart, SQLiteDatabase.GET_LOCK_LOG_PREFIX);
try {... ...
多线程读写
实现多线程读写的关键是enableWriteAheadLogging属性,这个方法 API Level 11添加的,也就是所3.0以上的版本就基本不可能实现真正的多线程读写了。简单的说通过调用enableWriteAheadLogging()和disableWriteAheadLogging()可以控制该数据是否被运行多线程读写,如果允许,它将允许一个写线程与多个读线程同时在一个SQLiteDatabase上起作用。实现原理是写操作其实是在一个单独的log文件,读操作读的是原数据文件,是写操作开始之前的内容,从而互不影响。当写操作结束后读操作将察觉到新数据库的状态。当然这样做的弊端是将消耗更多的内存空间。多线程写
这个就不用多想了,SQLite压根不支持,如果实在有需求可以使用多个数据库文件。备注
(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 SQLite3多线程的更多相关文章
- Android网络多线程断点续传下载
本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多 ...
- 教你如何在 Android 使用多线程下载文件
# 教你如何在 Android 使用多线程下载文件 前言 在 Android 日常开发中,我们会经常遇到下载文件需求,这里我们也可以用系统自带的 api DownloadManager 来解决这个问题 ...
- Android进阶——多线程系列之Thread、Runnable、Callable、Future、FutureTask
多线程一直是初学者最抵触的东西,如果你想进阶的话,那必须闯过这道难关,特别是多线程中Thread.Runnable.Callable.Future.FutureTask这几个类往往是初学者容易搞混的. ...
- android开发--多线程
android中的几种多线程实现方式: 1)Activity.runOnUiThread(Runnable) 2)View.post(Runnable) ;View.postDelay(Runnabl ...
- Android handle 多线程练习
Android handle <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android&quo ...
- Android SQLite3工具常用命令行总结
Android SDK的tools目录下提供了一个sqlite3.exe工具,这是一个简单的sqlite数据库管理工具.开发者可以方便的使用其对sqlite数据库进行命令行的操作. 程序运行生成的*. ...
- (原创)android Sqlite多线程访问异常解决方案
在开发Android的程序的时候sqlite数据库是经常用到的:在多线程访问数据库的时候会出现这样的异常:java.lang.IllegalStateException: Cannot perform ...
- 36.Android之多线程和handle更新UI学习
android经常用到多线程更新UI,今天学习下. 首先布局比较简单: <?xml version="1.0" encoding="utf-8"?> ...
- Android之多线程断点下载
本文主要包含多线程下载的一些简单demo,包括三部分 java实现 android实现 XUtils开源库实现 注意下载添加网络权限与SD卡读写权限 java实现多线程下载 public class ...
随机推荐
- bzoj2124 等差子序列(hash+线段树)
2124: 等差子序列 Time Limit: 3 Sec Memory Limit: 259 MBSubmit: 719 Solved: 261[Submit][Status][Discuss] ...
- html5---webworker多线程
javascript本身就是一个单线程的语言,一开始它的出现是为了简单的网页设计,设计者并没有考虑到多线程的问题,要知道,线程的开销是非常昂贵的.但是随着web开发的潮流化,javascript不是仅 ...
- hdu 4289 最小割,分拆点为边
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2609 #include <cstdio> #incl ...
- Directx 3D编程实例:随机绘制的立体图案旋转
最近朋友建议我写一些关于微软云技术的博客留给学校下一届的学生们看,怕下一届的MSTC断档.于是我也觉的有这个必要. 写了几篇博客之后,我觉得也有必要把这一年的学习内容放在博客做个纪念,就这样写了本篇博 ...
- pl sql developer登陆界面找不到oracle数据库选项
window 64位的操作系统 装的数据库win64_11gR2的数据库,PL SQL是PLSQL Developer 7.1.5最后是下载了一个instantclient_11_2包将你数据库安装路 ...
- php总结 --- 19. 其他小知识
1. PHP博物馆 php各个版本的代码库 2. PHP-GTK php桌面程序 3. Pecl 4. Pear 5. php调试器 目前还不清楚具体有什么大的优势,为什么要用, IDE不能满足吗 6 ...
- 面向新手的Webserver搭建(一)——IIS的搭建
非常多童鞋说自己是做移动开发的,想挂个简单的Web API,但是server又不会搭,这样一来測试就成了问题.看看网上的教程.发现略难懂,并且大多是一个转一个,没价值,所以干脆写几篇文章讲讲简单的We ...
- PermGen space错误解决方法
在看下文之前,首先要确认意见事情,就是你是怎样启动tomcat的,我们在平时的开发环境其中,都是通过startup.bat方式启动tomcat的,那么你依照以下的方式,去改动/bin/catalina ...
- iOS-获取UIView的全部层级结构
在iOS中获取UIView的全部层级结构 应用场景 在实际 iOS 开发中,非常多时候都须要知道某个 UI 控件中包括哪些子控件,而且分清楚它们的层级结构和自个的 frame 以及 bounds ,以 ...
- 根据IP地址获取IP的详细信息
<?php header('Content-Type:text/html; charset=utf-8'); function ip_data() { $ip = GetIP(); $url = ...