这类问题已被问到很多,但我找不到任何满足我的答案。
问题
我应该如何在多个线程上维护多个开放的SQLite连接?
是否可以检查打开的连接数,只有在没有连接时才调用close()?
修改
我接受了下面的答案,因为SQLite非常快并且同步所有sql API方法(一次只运行一个)可能不会太伤害。
话虽这么说,我仍然很高兴听到一个同步read()和write()的解决方案,以便可以一次完成多个read()...
背景
我正在构建一个Android应用程序,在某些地方我使用很少的Internet连接(GET请求)
当这些请求完成后,他们所有的线程都可以访问SQLite,大多数都是为了写入
当线程尝试同时连接时,我得到标题中提到的错误。
我知道为什么会发生:
我这样做,每个" SQLite API"方法(我写的API)首先打开连接,然后关闭它。无论何时需要,都使用写/读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'希望只要一个线程拥有这个变量,它就是唯一可以使用它的人 它显然不起作用,无论如何它只会减慢一切,我更喜欢更好的东西。
如何修复此逻辑?
答案 0 :(得分:1)
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();
}
}
注意用一个不返回任何东西的initialize函数替换getInstance(),并删除除createSomeEntry()和getSomeEntry()之外的所有其他公共函数。由于所有公共方法都在类上同步,因此一次只能有一个线程使用数据库,这可以解决SQLite不支持并发访问的问题。
如果您确实需要并发访问,我认为您的选择要么是要弄清楚如何从多个进程而不是多个线程访问SQLite数据库,这是满足我需要的方法,或者切换到另一个数据库。我想你也可以自己进行驱动程序更改,以使驱动程序真正成为多线程。