博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【翻译】Android多线程下安全访问数据库
阅读量:5827 次
发布时间:2019-06-18

本文共 3818 字,大约阅读时间需要 12 分钟。

为了记录如何线程安全地访问你的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 崩毁的原因。

        因此我们只能在确保数据库没有再被占用的情况下,才去关闭它。在   上有一些讨论推荐“永不关闭”你的 SQLiteDatabase 。  如果你这样做,你的logcat将会出现以下的信息,因此我不认为这是一个好主意。
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 来处理并发的情况

         现在你可以线程安全地使用你的数据库连接了。

 

         原文:  

转载地址:http://piadx.baihongyu.com/

你可能感兴趣的文章
海尔首创全程管家模式:从用户找海尔到海尔找用户
查看>>
腾讯游戏容器云平台的技术演进之路
查看>>
陪伴一家公司成长,戴尔易安信如何做到的
查看>>
孙杨:如果每一个中国人都用荣耀手机,我们的人民和国家会更强大
查看>>
猫眼确定2家基石投资者:最快春节前上市 腾讯表态支持
查看>>
因聚而生,以行致盛丨华为中国ICT生态之行2018走进齐齐哈尔
查看>>
展现千年科举历史的广东惠州古代科举制度陈列馆开馆
查看>>
福建泉州实行快捷通关模式 台轮“随到随检随走”
查看>>
BAT互联网公司,Java开发的最新招聘标准!
查看>>
「每天一道面试题」Semaphore的实现原理是什么?
查看>>
鸡西—哈尔滨—北京航线正式开通 促三地经贸交流
查看>>
山东检察机关适用认罪认罚从宽制度办理刑事案件3884件
查看>>
2018年,python的工资到底有多“吸金”?
查看>>
小米营销费用暴涨七成,但吴亦凡真的符合小米的气质吗?
查看>>
深度资讯|既要高抽成又要建生态,美团野心勃勃计划BC通吃
查看>>
百度、海淀区打造全球首个AI公园,北京人在家门口坐上无人车
查看>>
Servlet第六篇【Session介绍、API、生命周期、应用、与Cookie区别】
查看>>
Webpack2 的无脑友好错误提示工具
查看>>
Swift iOS : 如何一拖tableview到底的时候更新数据
查看>>
js千分位
查看>>