Java Android SQLite并发(尝试重新打开已关闭的连接)

Java Android SQLite并发(尝试重新打开已关闭的连接),java,android,multithreading,sqlite,Java,Android,Multithreading,Sqlite,这类问题被问了很多,但我找不到任何让我满意的答案 问题 如何在多个线程上维护多个打开的SQLite连接? 是否可以检查有多少连接处于打开状态,并仅在没有连接时调用close() 编辑 我接受了下面的答案,因为SQLite非常快,同步所有sql API方法(一次只运行一个)可能不会太痛苦。 尽管如此,我还是很高兴听到一个同步read()和write()的解决方案,这样就可以同时执行多个read() 背景 我正在构建一个Android应用程序,在某些地方我很少使用互联网连接(获取请求)。 当这些请求

这类问题被问了很多,但我找不到任何让我满意的答案

问题
如何在多个线程上维护多个打开的SQLite连接?
是否可以检查有多少连接处于打开状态,并仅在没有连接时调用close()

编辑
我接受了下面的答案,因为SQLite非常快,同步所有sql API方法(一次只运行一个)可能不会太痛苦。
尽管如此,我还是很高兴听到一个同步read()和write()的解决方案,这样就可以同时执行多个read()

背景
我正在构建一个Android应用程序,在某些地方我很少使用互联网连接(获取请求)。
当这些请求完成时,它们的所有线程都可以访问SQLite,大多数用于写入。
当线程试图同时连接时,我得到了标题中提到的错误

我知道为什么会这样:
按照我的方式,每个“SQLite API”方法(我编写的API)都是从打开连接开始,然后关闭连接结束。在需要时使用Write/read open()

因此,当一个线程关闭连接(API方法完成)而另一个线程仍在使用游标或其他任何东西时,就会发生错误并引发此异常

下面是一个代码示例来演示:

public class MySQL{
    private SQLiteOpenHelper mHelper;
    private SQLiteDatabase myDatabase;
    private static MySQL myInstance;
    ...

    //singleton
    public synchronized static MySQL getInstance(Context context){
        if(myInstance == null){
            myInstance = new MySQL(context);
        }
        synchronized (myInstance) {
            return myInstance;
        }
    }

    public SQLiteDatabase openRead() throws SQLException{
        return myDatabase = mHelper.getReadableDatabase();
    }


    public SQLiteDatabase openWrite() throws SQLException{ 
        return myDatabase = mHelper.getWritableDatabase();
    }

    //close helper
    public void close(){
        mHelper.close();
    }

    public static void createSomeEntry(){
         openWrite();
         myDatabase.query(...);
         ...
         close();
    }

    public static void getSomeEntry(){
         openRead();
         Cursor c = myDatabase.query(...);
         ...//use cursor in a loop
         close();
    }
}
假设这些方法的任意两个组合同时从不同的线程运行

如您所见,我尝试同步“myInstance”的使用/保持,希望只要一个线程保持此变量,它就是唯一可以使用它的线程。
它显然不起作用,而且它只会让一切都变慢,不管怎样,我更喜欢更好的


如何修复此逻辑?

SQLite的Java驱动程序不支持真正的并发多线程访问。从多个线程的使用不应损坏数据的意义上讲,这只是“线程安全”的。我认为最好的方法是打开一个连接,然后让每个线程在使用连接时锁定连接,在连接完成时锁定。我不太熟悉Android编程,但下面的方法可能会奏效:

public class MySQL{
    private static MySQL myInstance;
    private SQLiteOpenHelper mHelper;
    private SQLiteDatabase myDatabase;
    ...

    //initialize
    public synchronized static void initialize(Context context){
        if(myInstance == null){
            myInstance = new MySQL(context);
        }
    }

    public synchronized static void createSomeEntry() {
        myInstance.myDatabase = myInstance.mHelper.getWritableDatabase();
        myInstance.myDatabase.query(...);
        ...
        myInstance.mHelper.close();
    }

    public synchronized static void getSomeEntry() {
        myInstance.myDatabase = myInstance.mHelper.getReadableDatabase();
        Cursor c = myInstance.myDatabase.query(...);
        ...//use cursor in a loop
        myInstance.mHelper.close();
    }
}
请注意,将getInstance()替换为不返回任何内容的initialize函数,并删除除createSomeEntry()和getSomeEntry()之外的所有其他公共函数。由于类上的所有公共方法都是同步的,因此一次只能有一个线程使用数据库,这应该可以解决SQLite不支持并发访问的问题


如果您确实需要并发访问,我认为您的选择是要么找出如何从多个进程而不是多个线程访问SQLite数据库,这是适合我需要的方法,要么切换到另一个数据库。我想你也可以自己修改驱动程序,使驱动程序真正成为多线程的。

哦……我恐怕这就是答案。我觉得很奇怪,Android没有“Concurence API”。。。你能给我举一个锁定连接的例子吗?getInstance()方法中的解决方案有什么问题?谢谢我对Android特定的库不太熟悉,但您可以先将类中的所有内容设置为私有,除了createSomeEntry()和getSomeEntry()方法,这是您的其他代码将使用的唯一方法。同步createSomeEntry()和getSomeEntry()方法将处理客户端线程的争用。您可能需要在类内部进行一些额外的调整,但这只是一个开始。事实已经如此……使用这些函数的唯一方法是调用getInstance()。问题是,即使同步这些方法,也不意味着两个单独的方法不能同时访问数据库。必须有一个解决方案,使用类似于我的getInstance()方法的东西,同步实例……我要说的是使getInstance()方法也是私有的。客户端代码不会直接调用getInstance()。您只能在MySQL类中调用它。有趣的是……我如何更改代码,使其真正同步实例?我的意思是,光靠这一点解决不了问题。