Android多线程下操作sqlite数据库解决方案

问题:Android中的SQLite数据库并发访问

  • attempt to re-open an already-closed object
    因为我们只使用一个数据库连接,Thread1和Thread2的都是由getDatabase()方法返回的相同连接。发生的什么事呢,在Thread2还在使用数据库连接时,Thread1可能已经把它给关闭了,那就是为什么你会得到崩溃异常。

    我们需要确保在没有任何一个人在使用数据库时,才去关闭它。在StackOverflow上推荐的做法是永远不要关闭数据库。Android会尊重你这种做法,但会给你如下的提示。所以我一点也不推荐这种做法。

  • android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)

    每次都创建了一个新的SQLiteOpenHelper,实际上你每次都创建了一个数据库的连接。如果你在同一时间用不同的数据库连接来对同一的数据库进行写操作的话,那么其中一个会失败。

    解决方案:AtomicInteger

具体模拟代码(Android代码类似):

DataBaseManager

package com.gradle.java.thread;

import java.util.concurrent.atomic.AtomicInteger;

import com.gradle.android.utils.OkhttpUtils;

/**
 * @author Arison
 * 管理sqllite数据库
 */
public class DataBaseManager {

    private static DataBaseManager instance;

    /**
     * 保证多线程下原子操作
     */
    private  AtomicInteger i=new AtomicInteger();

    public static DataBaseManager getInstance(){
        if(instance==null){
            synchronized (DataBaseManager.class) {
                if (instance==null) {
                    OkhttpUtils.println("数据库管理类DataBaseManager--->单例初始化!");
                    instance=new DataBaseManager();
                }
            }
        }
        return instance;
    }

    /**
     * 模拟Android 数据库在多线程下的并发问题
     * @param args
     */
    public static void main(String[] args) {
        for(int i=1;i<=2000;i++){

            new Thread(new Runnable() {

                @Override
                public void run() {
                    //切记,打开,关闭数据库的操作不能直接SQLiteDatabase.getInstance().openDB();SQLiteDatabase.getInstance().closeDB();
                    //必须调用管理者单例类DataBaseManager 来调用打开和关闭操作,从而解决多线程下访问sqlite数据库的问题
                    DataBaseManager.getInstance().openDataBase();
                    DataBaseManager.getInstance().closeDataBase();
                }
            },""+i).start();
        }

    }

    public synchronized AtomicInteger openDataBase(){
        OkhttpUtils.println("+++++++++++++++++++++++++++++++++++++++++++");
        OkhttpUtils.println("线程"+Thread.currentThread().getName()+"--->open开始---->当前数据库连接数:"+i);
        if (i.incrementAndGet()==1) {
            OkhttpUtils.println("线程"+Thread.currentThread().getName()+"打开数据库之前!数据库状态:"
                    +SQLiteDatabase.getInstance().getStateDB());
            SQLiteDatabase.getInstance().openDB();//单例类模拟数据库打开操作
            OkhttpUtils.println("线程"+Thread.currentThread().getName()+"执行数据库打开操作!");
            OkhttpUtils.println("线程"+Thread.currentThread().getName()+"打开数据库之后!数据库状态:"
                    +SQLiteDatabase.getInstance().getStateDB());
        }else{
            OkhttpUtils.println("线程"+Thread.currentThread().getName()+"--->open()操作无效!新增一条数据库连接!---> 数据库状态:"
                    +SQLiteDatabase.getInstance().getStateDB());
        }
        OkhttpUtils.println("线程"+Thread.currentThread().getName()+"--->open完毕---->当前数据库连接数:"+i);
        OkhttpUtils.println("+++++++++++++++++++++++++++++++++++++++++++");
        return i;
    }

    public synchronized AtomicInteger closeDataBase(){
        OkhttpUtils.println("--------------------------------------------");
        OkhttpUtils.println("线程"+Thread.currentThread().getName()+"--->close开始---->当前数据库连接数:"+i);
        if (i.decrementAndGet()==0) {

            OkhttpUtils.println("线程"+Thread.currentThread().getName()+"关闭数据库之前!数据库状态:"
                    +SQLiteDatabase.getInstance().getStateDB());
            SQLiteDatabase.getInstance().closeDB();//单例类模拟数据库关闭操作
            OkhttpUtils.println("线程"+Thread.currentThread().getName()+"执行数据库关闭操作!");
            OkhttpUtils.println("线程"+Thread.currentThread().getName()+"关闭数据库之后!数据库状态:"
                    +SQLiteDatabase.getInstance().getStateDB());

        }else{
            OkhttpUtils.println("线程"+Thread.currentThread().getName()+"--->close()操作无效!关闭一条数据库连接!--->数据库状态:"
                    +SQLiteDatabase.getInstance().getStateDB());
        }
        OkhttpUtils.println("线程"+Thread.currentThread().getName()+"--->close完毕---->当前数据库连接数:"+i);
        OkhttpUtils.println("--------------------------------------------");
        return i;
    }

}

SQLiteDatabase

package com.gradle.java.thread;


/**
 * @author Arison
 * 模拟Android sqlite数据库
 */
public class SQLiteDatabase {

    private static SQLiteDatabase instance;

    private boolean isOpen=false;

    public static SQLiteDatabase getInstance(){
         if(instance==null){
             synchronized (SQLiteDatabase.class) {
                if (instance==null) {
                    instance=new SQLiteDatabase();
                }
            }
         }
        return instance;
    }

    public  void openDB(){
        this.isOpen=true;
    }

    public  void  closeDB(){
        this.isOpen=false;
    }

    public  boolean getStateDB(){
        return isOpen;
    }
}

运行效果图(局部):

这里写图片描述
这里写图片描述

项目代码:

github【Gradle-demo】

联系方式:

见左边栏目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Arisono

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值