我正在阅读有关此问题的stackoverflow,但我仍然没有找到解决方案。我注意到有时,我的应用程序会抛出此错误:
java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:962)
at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:599)
at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
...
我有一个名为DatabaseHelper.java的文件,使用这种方法获取它的实例:
public static DatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
}
return mInstance;
}
然后我有类似这样的方法(它在行cursor.moveToFirst()中崩溃并出现该错误)。它几乎不会崩溃,但有时会崩溃。
public Profile getProfile(long id) {
SQLiteDatabase db = this.getReadableDatabase();
String selectQuery = "SELECT * FROM " + TABLE_PROFILES + " WHERE " + KEY_PROFILES_ID + " = " + id;
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
Profile profile = new Profile();
if (cursor.moveToFirst()) {
doWhatEver();
}
cursor.close();
db.close();
return profile;
}
就是这样,在我使用的所有方法中:
SQLiteDatabase db = this.getReadableDatabase(); (or Writable)
然后我关闭光标和数据库。在这种情况下,错误就行了:
cursor.moveToFirst();
如果我之前调用this.getReadableDatabase(),我不明白为什么错误说数据库已关闭。请支持!谢谢:))
答案 0 :(得分:74)
删除
db.close();
如果在关闭数据库后尝试其他操作,它将为您提供该异常。
释放对象的引用,关闭对象......
另外,退房 Android Sq Lite closed exception关于来自Android Framework工程师的评论,该评论声明关闭数据库连接不是必需的。
答案 1 :(得分:17)
我目前遇到同样的问题。虽然删除db.close()为我解决了问题,但我认为这个问题是由多线程引起的。这是我的研究。
SQLiteOpenHelper保存对SQLiteDatabase的引用,当调用getReadableDatabase()或getWritableDatabase()时,它将返回引用,如果SQLiteDatabase 关闭或为null,则将创建新的SQLiteDatabase对象。请注意,在get方法中,代码在同步块中受到保护。
SQLiteDatabase是SQLiteClosable的子类。 SQLiteClosable实现了引用计数方案。
首次创建时,计数为1.
当数据库操作方法运行时(如insert,query),它会增加计数,并在方法结束时减少计数。但是游标操作不受引用计数的保护。
如果计数减少到0,则连接池将关闭,成员SQLiteConnectionPool对象将设置为null,现在SQLiteDatabase 已关闭;
SQLiteDatabase.close()会将计数减少1;
因此,如果你有一个单线程方案,关闭SQLiteDatabase就可以了,因为SQLiteOpenHelper只会重新创建它。
如果你做多线程,那么你会遇到麻烦。假设线程A和线程B都调用getReadableDatabase(),并且SQLiteOpenHelper返回它保存的SQLiteDatabase,然后线程A首先完成其操作并调用SQLiteDatabase.close(),现在SQLiteDatabase对象线程B已经关闭所以任何后续的db操作调用或游标方法调用都会抛出异常。
答案 2 :(得分:3)
我遇到了同样的问题,无法修复它。我找到了一条可能的线索: 我有一个一直在运行的同步线程:
Item ii = dbHelper.popPendingUpload();
if (ii != null)
upload(ii);
在DBHelper里面
public Item popPendingUpload() {
SQLiteDatabase db = getReadableDatabase();
Cursor res = db
.rawQuery("SELECT * FROM items WHERE state = 0 LIMIT 1",
new String[] {});
boolean hasNext = res.moveToFirst();
Item ii = null;
if (hasNext) {
ii = //load item
}
db.close();
return ii;
}
错误也会出现在moveToFirst()方法调用中。当线程在无限循环中弹出项目时,第一次它正常工作,第二次出现错误。有趣的是,如果我放置一个断点并逐步执行代码,则错误不再显示。我正在使用Android 4.1在真实设备上进行测试。
我知道,这不是一个答案,但它可能有所帮助。我会继续测试。
答案 3 :(得分:3)
//close database after cursor is closed like:
if(cursor.getCount() != 0){
while(cursor.moveToNext()){
//do operation
}
}
cursor.close();
database.close();
答案 4 :(得分:0)
也许您在从应用访问数据库之前关闭了数据库。
您必须将getProfile()编辑为
class FooClass(object):
def __init__(self, *args, **kwargs):
self.foos = ["foo", "bar"]
def do_foos(self):
for foo in self.foos:
print("I have a " + foo)
class SpecialisedFooClass(FooClass):
def __init__(self, *args, **kwargs):
super(SpecialisedFooClass, self).__init__(*args, **kwargs)
self.foos.append("spec")
答案 5 :(得分:0)
我有一个像你这样的错误,这里是我的代码:
try {
String sql = "SELECT * FROM "+DB_TABLEDOWNLOAD;
Cursor cursor = db.rawQuery(sql, null);
//空双引号为原表没有的字段
String temp = "";
int existIconPath = cursor.getColumnIndex("iconPath");
int existAudioID = cursor.getColumnIndex("audioID");
if (existIconPath == -1 && existAudioID == -1){
temp = "url, downed,total,path,name, audioTitle, audioFileID,\"\",\"\"";
}else if (existIconPath == -1 && existAudioID != -1){//iconPath不存在
temp = "url, downed,total,path,name, audioTitle, audioFileID,\"\",audioID";
}else if (existIconPath != -1 && existAudioID == -1){//audioID不存在
temp = "url, downed,total,path,name, audioTitle, audioFileID,iconPath,\"\"";
}else {
return;
}
db.beginTransaction();
String tempTableName = "_temp_"+DB_TABLEDOWNLOAD;
String sqlCreateTemp = " ALTER TABLE "+DB_TABLEDOWNLOAD+" RENAME TO "+tempTableName+";";
db.execSQL(sqlCreateTemp);
final String TB_TESTPAPERINFO_CREATE = "Create TABLE IF NOT EXISTS "
+ DB_TABLEDOWNLOAD
+ "(url TEXT, downed TEXT,total TEXT,path TEXT,name TEXT, audioTitle TEXT, audioFileID TEXT,iconPath TEXT, audioID TEXT);";
db.execSQL(TB_TESTPAPERINFO_CREATE);
String sqlBackupData = "INSERT INTO "+DB_TABLEDOWNLOAD+" SELECT "+temp+" FROM "+tempTableName+";";
db.execSQL(sqlBackupData);
String sqlDrop = "DROP TABLE IF EXISTS '"+tempTableName+"';";
db.execSQL(sqlDrop);
db.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
}finally{
db.endTransaction();
}
我在db.beginTransaction()之前使用return,我的代码在beginTransaction之前返回,但是我终于在endTransaction中。如果你没有beginTransaction和endTransaction,则会出现异常。
请检查有关db.beginTransaction和endTransaction的代码。
答案 6 :(得分:0)
这是使用getApplicationContext()初始化房间数据库的Android体系结构中的一个简单错误,这意味着您的应用程序具有数据库引用的一个实例,无论有多少活动创建了该实例的实例,因此如果在其中关闭它任何其他活动都会引发该异常。
本质上,不只是检查引发异常的活动,而是db.close()的每个活动
答案 7 :(得分:0)
如果有人在搜索这篇文章时遇到同样的情况,请提一下出现此错误的另一种可能性:
在 Android Studio 中使用 Database Inspector 在某些情况下可能会导致此错误。