Java Android:无法执行此操作,因为连接池已关闭
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23293572/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android: Cannot perform this operation because the connection pool has been closed
提问by Ferran Negre
I was reading through StackOverflow about this question and I still haven't found a solution. I notice that sometimes, my app throws this error:
我正在阅读有关此问题的 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)
...
I have a file called DatabaseHelper.java
using this approach to get an instance of it:
我有一个DatabaseHelper.java
使用这种方法调用的文件来获取它的实例:
public static DatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
}
return mInstance;
}
Then I have methods like this one (that it crashed in the line cursor.moveToFirst()
with that error). It almost never crashes, but sometimes it does.
然后我有这样的方法(它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;
}
So that's it, in all the methods I use:
就是这样,在我使用的所有方法中:
SQLiteDatabase db = this.getReadableDatabase(); (or Writable)
And then I close the cursor and the db. In this case, the error got throw in the line:
然后我关闭游标和数据库。在这种情况下,错误在行中抛出:
cursor.moveToFirst();
I do not see why the error says the db is closed if I am calling this.getReadableDatabase()
before. Please support! Thank you :)
如果我this.getReadableDatabase()
之前打电话,我不明白为什么错误说数据库已关闭。请支持!谢谢 :)
采纳答案by AmmarCSE
Remove
消除
db.close();
If you try another operation after closing the database, it will give you that exception.
如果您在关闭数据库后尝试另一个操作,它会给您那个异常。
The documentationsays:
该文件说:
Releases a reference to the object, closing the object...
释放对对象的引用,关闭对象...
Also, check out Android Sq Lite closed exceptionabout a comment from an Android Framework engineer which states that it is not neccesary to close the database connection.
此外,请查看 Android Sq Lite 关闭异常,该异常是关于 Android 框架工程师的评论,该评论指出关闭数据库连接不是必需的。
回答by Jason Oviedo
I am having the same problem, have not been able to fix it. I have found a possible clue: I have a sync thread that is running all the time:
我遇到了同样的问题,一直无法解决。我找到了一个可能的线索:我有一个一直在运行的同步线程:
Item ii = dbHelper.popPendingUpload();
if (ii != null)
upload(ii);
And inside DBHelper
在 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;
}
The error also shows up in the moveToFirst() method call. As the thread is poping items out in an infinite loop, the first time it works ok, the second time the error appears. The interesting part is that if I put a breakpoint and step through the code, the error does not show any more. I am testing on a real device using Android 4.1.
该错误也出现在 moveToFirst() 方法调用中。由于线程在无限循环中弹出项目,第一次工作正常,第二次出现错误。有趣的部分是,如果我放置一个断点并单步执行代码,错误将不再显示。我正在使用 Android 4.1 的真实设备上进行测试。
I know, is not an answer, but it may help. I'll keep on testing.
我知道,这不是答案,但可能会有所帮助。我会继续测试。
回答by yaginier
Maybe you close the database before access to database from your app.
也许您在从应用程序访问数据库之前关闭了数据库。
You have to edit getProfile() to
您必须将 getProfile() 编辑为
public Profile getProfile(long id) {
SQLiteDatabase db = this.getReadableDatabase();
try {
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();
finally {
db.close();
}
return profile;
}
回答by handhand
I currently have the same problem. While removing the db.close()
solves the issue for me, I think the issue is caused by multi-threading. Here is my research.
我目前有同样的问题。虽然删除db.close()
为我解决了问题,但我认为问题是由多线程引起的。这是我的研究。
SQLiteOpenHelper
holds a reference to SQLiteDatabase
, when getReadableDatabase()
or getWritableDatabase()
called, it will return the reference, if the SQLiteDatabase
is closedor null, a new SQLiteDatabase
object will be created. Note that inside the get method, codes are guarded in a synchronized block.
SQLiteOpenHelper
拥有一个参考SQLiteDatabase
,当getReadableDatabase()
或getWritableDatabase()
调用,它将返回引用,如果SQLiteDatabase
被关闭或无效,新的SQLiteDatabase
对象将被创建。请注意,在 get 方法内部,代码在同步块中受到保护。
SQLiteDatabase
is a subclass of SQLiteClosable
. SQLiteClosable
implements a reference counting scheme.
SQLiteDatabase
是 的子类SQLiteClosable
。SQLiteClosable
实现引用计数方案。
When first created, the count is 1.
When the database operation methods run (like insert, query), it will increase the count, and decrease the count when methods end. But the cursor operations are NOT protected by reference counting.
If the count decreases to 0, connection pool will be closed and a member
SQLiteConnectionPool
object will be set to null, and now theSQLiteDatabase
is closed;SQLiteDatabase.close()
will decrease the count by 1;
首次创建时,计数为 1。
当数据库操作方法运行时(如插入、查询),它会增加计数,并在方法结束时减少计数。但是游标操作不受引用计数保护。
如果计数减少到 0,连接池将被关闭,并且一个成员
SQLiteConnectionPool
对象将被设置为 null,现在SQLiteDatabase
被关闭;SQLiteDatabase.close()
将计数减 1;
So, if you have a single-threaded scheme, closing the SQLiteDatabase
will be fine because SQLiteOpenHelper
will just re-recreate it.
所以,如果你有一个单线程方案,关闭它SQLiteDatabase
会很好,因为SQLiteOpenHelper
它只会重新创建它。
If you do multi-threading, then you will run into trouble. Say thread A and thread B both call getReadableDatabase()
, and SQLiteOpenHelper
returns the SQLiteDatabase it holds, and then thread A first finished its operation and call SQLiteDatabase.close()
, now the SQLiteDatabase
object thread B has is closedso any subsequent db operation calls or cursor method calls will throw the exception.
如果你做多线程,那么你会遇到麻烦。假设线程 A 和线程 B 都调用getReadableDatabase()
,并SQLiteOpenHelper
返回其持有的 SQLiteDatabase,然后线程 A 首先完成其操作和调用SQLiteDatabase.close()
,现在SQLiteDatabase
线程 B 拥有的对象已关闭,因此任何后续的 db 操作调用或游标方法调用都会抛出异常。
回答by Mohammad nabil
//close database after cursor is closed like:
if(cursor.getCount() != 0){
while(cursor.moveToNext()){
//do operation
}
}
cursor.close();
database.close();
回答by doordoor
I have a error like yours ,here my code:
我有一个像你一样的错误,这是我的代码:
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();
}
I use return before db.beginTransaction(),my code return before beginTransaction,but I endTransaction in finally . if you do not beginTransaction and endTransaction ,the exception will appear.
我在 db.beginTransaction() 之前使用 return,我的代码在 beginTransaction 之前返回,但我 endTransaction 在 finally 中。如果您没有 beginTransaction 和 endTransaction ,则会出现异常。
so check your code about the db.beginTransaction and endTransaction.
因此,请检查有关 db.beginTransaction 和 endTransaction 的代码。
回答by E-max
This is a simple error in Android architecture initialisation of room database with getApplicationContext(), this means that your application has one instance of the database reference, no matter how many activities create an instance of it, therefore if you close it in any activity the others will throw that exception.
这是使用 getApplicationContext() 初始化房间数据库的 Android 架构中的一个简单错误,这意味着您的应用程序具有数据库引用的一个实例,无论有多少活动创建了它的实例,因此如果您在任何活动中关闭它其他人会抛出那个异常。
Essentially don't just check the activity throwing the exception but every activity for db.close()
本质上不要只检查引发异常的活动,而是检查 db.close() 的每个活动