我有一個內容提供商支持SQLiteDatabase
。請看下面的兩個調用:對內容提供者連續調用的執行順序是否保證(在一個線程內)?
//the following call results in "DELETE FROM DETAILS":
context.getContentResolver().delete(getContentUriOfDetailTable(), null, null); //line 1
//the following call results in "DELETE FROM MASTER":
context.getContentResolver().delete(getContentUriOfMasterTable(), null, null); //line 2
據我所知內容提供商are thread safe, when backed by an SQLiteDatabase。但是有沒有保證,第1行觸發的SQL的執行是在第2行觸發的SQL執行之前完成的?
背景: 有從表詳細信息掌握一門重要的參考,我得到了一個bug報告
SQLiteConstraintException: foreign key constraint failed (code 19)
從第2行,雖然我不能複製。
表:
CREATE TABLE MASTER
(_id PRIMARY KEY autoincrement,
VALUE text
);
CREATE TABLE DETAILS (
_id PRIMARY KEY autoincrement,
MASTERIDX integer not null,
VALUE text,
FOREIGN KEY(MASTERIDX) REFERENCES MASTER(_id)
);
我的ContentProvider是沒什麼特別的:
public class MyDbContentProvider extends ContentProvider {
private MyDbOpenHelper mDbHelper;
//...
//...
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = mDbHelper.getWritableDatabase();
int rowsDeleted = 0;
String where;
MyUriMatcher.MatchResult matchRes = mURIMatcher.matchTable(uri);
TableDef tableDef = matchRes.tableDef;
switch (matchRes.uriType) {
case ALL_ITEMS:
where = selection;
break;
case SINGLE_ITEM:
String idstr = uri.getLastPathSegment();
where = TableDef._ID + " = " + idstr;
if (!TextUtils.isEmpty(selection)) {
where += " AND (" + selection + ")";
}
break;
default:
throw new IllegalArgumentException("Unsupported URI for delete: " + uri);
}
try {
rowsDeleted = db.delete(tableDef.getTableName(), where, selectionArgs);
} catch (SQLException e) {
throw createCustomSqlException(e, "DELETE", uri, null, where, selectionArgs);
}
// notify all listeners of changes:
if (rowsDeleted > 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return rowsDeleted;
}
}
這裏是堆棧跟蹤:
android.database.SQLException: SQLiteConstraintException: foreign key constraint failed (code 19) for DELETE for following URI: content://de.myapp.mobil.myappDbProvider/master and this selection: null
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:858)
at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:754)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
at android.database.sqlite.SQLiteDatabase.delete(SQLiteDatabase.java:1494)
at de.myapp.mobil.MyDbContentProvider.delete(MyDbContentProvider.java:267)
at android.content.ContentProvider$Transport.delete(ContentProvider.java:228)
at android.content.ContentResolver.delete(ContentResolver.java:958)
at de.myapp.CommonDbContract$TableDef.deleteAll(CommonDbContract.java:119)
at de.myapp.mobil.MyDbContract.deleteAll(MyDbContract.java:1730)
at de.myapp.mobil.MyDbContract.recreateDbOrDeleteAll(MyDbContract.java:1761)
at de.myapp.mobil.SettingsActivity$ResetAllCommand.execute(SettingsActivity.java:77)
at de.myapp.mobil.SettingsActivity$ResetAllCommand.execute(SettingsActivity.java:1)
at de.myapp.DlgUtils$DataCommand.execute(DlgUtils.java:54)
at de.myapp.DlgUtils$CombinedCommand.execute(DlgUtils.java:116)
at de.myapp.DlgUtils$CommandWrapper.onClick(DlgUtils.java:157)
您確定沒有其他應用程序或線程同時訪問提供程序嗎?另一個線程可能會在上述兩個調用之間進行調用,修改MASTER表的方式會導致第2行調用失敗。 –
只有一個應用程序正在訪問此數據庫。但我不能排除,因爲主要活動有[launchMode singleTop而不是singleTask](http://stackoverflow.com/q/16693191/2306907),所以不存在應用程序的另一個實例。但我無法想象兩個實例修改此表的實際情況,因爲這都是用戶驅動的。因此,您將不得不以光速切換屏幕,因爲不存在添加數據的後臺進程。 –
要回答你的原始問題:是的,你的兩條線將在你的線程中順序運行。與「ContentProvider」的通信發生在屏幕後面的「Binder」調用。在ContentProvider方面,它應該也是順序執行的。但是,這取決於實施。如果它正在做一些事情,比如產生一個線程來處理刪除操作,那麼它可能是爭用的原因。雖然這可能不太可能。有一件事我不明白:你的MASTER表有什麼外鍵? –