【翻译】Android多线程下安全访问数据库
publicclassDatabaseHelperextendsSQLiteOpenHelper{...}
现在你想在不同的线程中对数据库进行写数据操作:
// Thread 1Context context = getApplicationContext();DatabaseHelper helper =newDatabaseHelper(context);SQLiteDatabase database = helper.getWritableDatabase();
database.insert(…);
database.close();// Thread 2Context context = getApplicationContext();DatabaseHelper helper =newDatabaseHelper(context);SQLiteDatabase database = helper.getWritableDatabase();
database.insert(…);
database.close();
然后在你的Logcat中将输出类似下面的日志信息,而你的写数据操作将会无效。
android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)
上面问题的出现,源于你每创建一个 SQLiteOpenHelper 对象时,实际上也是在新建一个数据库连接。如果你尝试通过多个连接同时对数据库进行写数据操作,其一定会失败。
为确保我们能在多线程中安全地操作数据库,我们需要保证只有一个数据库连接被占用。
我们先编写一个负责管理单个 SQLiteOpenHelper 对象的单例 DatabaseManager 。
publicclassDatabaseManager{privatestaticDatabaseManager instance;privatestaticSQLiteOpenHelper mDatabaseHelper;publicstaticsynchronizedvoid initialize(Context context,SQLiteOpenHelper helper){if(instance ==null){
instance =newDatabaseManager();
mDatabaseHelper = helper;}}publicstaticsynchronizedDatabaseManager getInstance(){if(instance ==null){thrownewIllegalStateException(DatabaseManager.class.getSimpleName()+" is not initialized, call initialize(..) method first.");}return instance;}publicsynchronizedSQLiteDatabase getDatabase(){returnnew mDatabaseHelper.getWritableDatabase();}}
为了能在多线程中进行写数据操作,我们得修改一下代码,具体如下:
// In your application classDatabaseManager.initializeInstance(getApplicationContext());// Thread 1DatabaseManager manager =DatabaseManager.getInstance();SQLiteDatabase database = manager.getDatabase()
database.insert(…);
database.close();// Thread 2DatabaseManager manager =DatabaseManager.getInstance();SQLiteDatabase database = manager.getDatabase()
database.insert(…);
database.close();
然后又导致另个崩毁
java.lang.IllegalStateException: attempt to re-open an already-closed object:SQLiteDatabase
既然我们只有一个数据库连接,Thread1 和 Thread2 对方法 getDatabase() 的调用就会取得一样的 SQLiteDatabase 对象实例。之后的事情就是,当 Thread1 尝试管理数据库连接时,Thread2 却仍然在使用该数据库连接。这也就是导致 IllegalStateException 崩毁的原因。
Leak foundCaused by: java.lang.IllegalStateException:SQLiteDatabase created and never closed
示例:
publicclassDatabaseManager{privateAtomicInteger mOpenCounter =newAtomicInteger();privatestaticDatabaseManager instance;privatestaticSQLiteOpenHelper mDatabaseHelper;privateSQLiteDatabase mDatabase;publicstaticsynchronizedvoid initializeInstance(SQLiteOpenHelper helper){if(instance ==null){
instance =newDatabaseManager();
mDatabaseHelper = helper;}}publicstaticsynchronizedDatabaseManager getInstance(){if(instance ==null){thrownewIllegalStateException(DatabaseManager.class.getSimpleName()+" is not initialized, call initializeInstance(..) method first.");}return instance;}publicsynchronizedSQLiteDatabase openDatabase(){if(mOpenCounter.incrementAndGet()==1){// Opening new database
mDatabase = mDatabaseHelper.getWritableDatabase();}return mDatabase;}publicsynchronizedvoid closeDatabase(){if(mOpenCounter.decrementAndGet()==0){// Closing database
mDatabase.close();}}}
然后你可以怎样子去调用它:
SQLiteDatabase database =DatabaseManager.getInstance().openDatabase();
database.insert(...);// database.close(); Don't close it directly!DatabaseManager.getInstance().closeDatabase();// correct way
以后每当你需要使用数据库连接,你可以通过调用类 DatabaseManager 的方法openDatabase()。在方法里面,内置一个标志数据库被打开多少次的计数器。如果计数为1,代表我们需要打开一个新的数据库连接,否则,数据库连接已经存在。
在方法 closeDatabase() 中,情况也一样。每次我们调用 closeDatabase() 方法,计数器都会递减,直到计数为0,我们就需要关闭数据库连接了。
提示: 你应该使用 AtomicInteger 来处理并发的情况
现在你可以线程安全地使用你的数据库连接了。
【翻译】Android多线程下安全访问数据库的更多相关文章
- Android多线程下安全访问数据库
http://zhiwei.neatooo.com/blog/detail?blog=5343818a9d4869f0310000de github 原文https://github.com/dmyt ...
- Android 使用MySQL直接访问数据库
在实际项目中,一般很少直接访问MySQL数据库,一般情况下会通过http请求将数据传送到服务端,然后在服务端连接mysql数据库. 在android 中,会通过使用Jdbc 连接MySQL 服务器 p ...
- springboot-oracle工程win下正常,centos下不能访问数据库
工程在win下正常运行,部署到centos下出现下述异常: ### Error querying database. Cause: org.springframework.jdbc.CannotGet ...
- ASP.NET MVC Filters 4种默认过滤器的使用【附示例】 数据库常见死锁原因及处理 .NET源码中的链表 多线程下C#如何保证线程安全? .net实现支付宝在线支付 彻头彻尾理解单例模式与多线程 App.Config详解及读写操作 判断客户端是iOS还是Android,判断是不是在微信浏览器打开
ASP.NET MVC Filters 4种默认过滤器的使用[附示例] 过滤器(Filters)的出现使得我们可以在ASP.NET MVC程序里更好的控制浏览器请求过来的URL,不是每个请求都会响 ...
- 无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)
1.android下junit测试框架配置 单元测试需要在手机中进行安装测试 (1).在清单文件中manifest节点下配置如下节点 <instrumentation android:name= ...
- Android 异步任务,通过PHP访问数据库,多线程,线程间通讯
文章列表MainActivity.java package com.eric.asynctask; import java.io.IOException; import java.util.Array ...
- sqlserver 服务器主体 无法在当前安全上下文下访问数据库
今天使用sqlserver,发现了一个问题,就是使用 insert into 数据库名.dbo.表名(字段) values(值) 这样语句的时候,会返回错误: sqlserver 服务器主体 无法在当 ...
- IOS 使用FMDB多线程访问数据库 及databaseislocked的问题
原理:文件数据库sqlite,同一时刻允许多个进程/线程读,但同一时刻只允许一个线程写.在操行写操作时,数据库文件被琐定,此时任何其他读/写操作都被阻塞,如果阻塞超过5秒钟(默认是5秒,能过重新编译s ...
- sql server service broker中调用存储过程执行跨库操作,不管怎么设置都一直提示 服务器主体 "sa" 无法在当前安全上下文下访问数据库 "dbname"。
用sql server自带的消息队列service borker,调用存储过程中,执行了一个跨库的操作,先是用了一个用户,权限什么都给够了,但是一直提示 服务器主体 "user" ...
随机推荐
- Petuum - Careers
Petuum - Careers Cloudformation
- 线性稳压器 (LDO)
线性稳压器 (LDO) 当输出电压低于输入电压时,必须从负载电源和压降比来考虑要采用线性稳压器 (LDO) 或降压转换器 (Buck) 低压降线性稳压器 (LDO) 适合用在需求低噪讯.低电流和低压降 ...
- Linux 系统 /proc/[pid]/stat 文件解释
转载:http://www.net527.cn/a/caozuoxitong/Linux/2012/0823/24385.html [root@localhost ~]# cat /proc/6873 ...
- 使用wget提示无法建立SSL连接
wget 下载URL 提示无法建立SSL连接 解决方法: 原命令上加上" --no-check-certificate" 这是因为wget在使用HTTPS协议时,默认会去验证网站的 ...
- 最好的 NMAP 扫描策略
# 适用所有大小网络最好的 nmap 扫描策略 # 主机发现,生成存活主机列表 $ nmap -sn -T4 -oG Discovery.gnmap 192.168.56.0/24 $ grep &q ...
- 发布一个C++版本的ORM库SmartDB
先简单说说ORM的优点: 提高开发效率,减少重复劳动,只和业务实体打交道,由业务实体自动生成sql语句,不用手写sql语句. 简单易用, 可维护性好. 隔离数据源,使得我们更换数据源时不用修改代码. ...
- Error: Cannot find module 'internal/fs'
$ sudo n 6.9.1 $ sudo npm -g install npm@next $ sudo n stable curl -0 -L https://npmjs.org/install.s ...
- jquery hide和show方法
html 元素的显示和隐藏hide() 如果被选的元素已被显示,则隐藏该元素. show() 如果被选的元素已被隐藏,则显示该元素. <html> <head> <scr ...
- 循环链表的创建、插入、删除、逆序、显示(C++实现)
对于单链表,因为每一个结点仅仅存储了向后的指针.到了尾标志就停止了向后链的操作,这样,其中某一结点就无法找到它的前驱结点了. 对于单链表的操作大家能够看我的这篇博客http://blog.csdn.n ...
- TensorFlowIO操作(三)------图像操作
图像操作 图像基本概念 在图像数字化表示当中,分为黑白和彩色两种.在数字化表示图片的时候,有三个因素.分别是图片的长.图片的宽.图片的颜色通道数.那么黑白图片的颜色通道数为1,它只需要一个数字就可以表 ...