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

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qingfeng812/article/details/62217743 问题:Android中的SQLite数据库并发访问attempt to re-open an already-closed object 因为我们只使用一个数据库连接,Thread1和Thread2的都是由getDatabase()方法返回的相同连接。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qingfeng812/article/details/62217743

问题: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】

联系方式:

见左边栏目

相关文章
|
JavaScript 关系型数据库 MySQL
❤Nodejs 第六章(操作本地数据库前置知识优化)
【4月更文挑战第6天】本文介绍了Node.js操作本地数据库的前置配置和优化,包括处理接口跨域的CORS中间件,以及解析请求数据的body-parser、cookie-parser和multer。还讲解了与MySQL数据库交互的两种方式:`createPool`(适用于高并发,通过连接池管理连接)和`createConnection`(适用于低负载)。
17 0
|
29天前
|
API 数据库 C语言
【C/C++ 数据库 sqlite3】SQLite C语言API返回值深入解析
【C/C++ 数据库 sqlite3】SQLite C语言API返回值深入解析
169 0
|
1月前
|
SQL 数据库连接 数据库
你不知道ADo.Net中操作数据库的步骤【超详细整理】
你不知道ADo.Net中操作数据库的步骤【超详细整理】
16 0
|
1月前
|
存储 SQL 关系型数据库
TiDB的优势:为何选择TiDB作为您的数据库解决方案
【2月更文挑战第25天】随着数据规模的不断增长和业务需求的日益复杂化,现代企业对数据库系统的扩展性、高可用以及分布式处理能力提出了更高的要求。TiDB作为一个新型的开源分布式数据库,以其独特的设计理念与卓越的技术特性,在众多数据库解决方案中脱颖而出。本文将深入剖析TiDB的核心优势,探讨其如何帮助企业从容应对海量数据挑战、实现无缝水平扩展、保障服务高可用性,并提供灵活一致的事务支持。
|
11天前
|
SQL 关系型数据库 数据库
Python中SQLite数据库操作详解:利用sqlite3模块
【4月更文挑战第13天】在Python编程中,SQLite数据库是一个轻量级的关系型数据库管理系统,它包含在一个单一的文件内,不需要一个单独的服务器进程或操作系统级别的配置。由于其简单易用和高效性,SQLite经常作为应用程序的本地数据库解决方案。Python的内置sqlite3模块提供了与SQLite数据库交互的接口,使得在Python中操作SQLite数据库变得非常容易。
|
11天前
|
Java API 调度
安卓多线程和并发处理:提高应用效率
【4月更文挑战第13天】本文探讨了安卓应用中多线程和并发处理的优化方法,包括使用Thread、AsyncTask、Loader、IntentService、JobScheduler、WorkManager以及线程池。此外,还介绍了RxJava和Kotlin协程作为异步编程工具。理解并恰当运用这些技术能提升应用效率,避免UI卡顿,确保良好用户体验。随着安卓技术发展,更高级的异步处理工具将助力开发者构建高性能应用。
|
15天前
|
存储 关系型数据库 MySQL
【mybatis-plus】Springboot+AOP+自定义注解实现多数据源操作(数据源信息存在数据库)
【mybatis-plus】Springboot+AOP+自定义注解实现多数据源操作(数据源信息存在数据库)
|
16天前
|
关系型数据库 MySQL 数据库连接
Python+SQLite数据库实现服务端高并发写入
Python中使用SQLite内存模式实现高并发写入:创建内存数据库连接,建立表格,通过多线程并发写入数据。虽然能避免数据竞争,但由于SQLite内存模式采用锁机制,可能在高并发时引发性能瓶颈。若需更高性能,可选择MySQL或PostgreSQL。
19 0
|
22天前
|
安全 Linux API
Android进程与线程
Android进程与线程
18 0
|
1月前
|
缓存 监控 安全
宝塔数据库崩溃解决方案详解
宝塔数据库崩溃解决方案详解