在尝试删除引用为外键的行时(出于实验目的),我得到了运行时异常。我知道我试图违反外键约束,我只是对logcat消息感到困惑,因为它引用了我的代码中完全不同的部分。
这是我的SQLiteOpenHelper
onCreate
方法:
@Override
public void onCreate(SQLiteDatabase db) {
this.db = db;
final String SQL_CREATE_CATEGORIES_TABLE = "CREATE TABLE " +
CategoriesTable.TABLE_NAME + "( " +
CategoriesTable._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
CategoriesTable.COLUMN_NAME + " TEXT " +
")";
final String SQL_CREATE_QUESTIONS_TABLE = "CREATE TABLE " +
QuestionsTable.TABLE_NAME + " ( " +
QuestionsTable._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
QuestionsTable.COLUMN_QUESTION + " TEXT, " +
QuestionsTable.COLUMN_OPTION1 + " TEXT, " +
QuestionsTable.COLUMN_OPTION2 + " TEXT, " +
QuestionsTable.COLUMN_OPTION3 + " TEXT, " +
QuestionsTable.COLUMN_ANSWER_NR + " INTEGER, " +
QuestionsTable.COLUMN_DIFFICULTY + " TEXT, " +
QuestionsTable.COLUMN_CATEGORY + " INTEGER, " +
"FOREIGN KEY(" + QuestionsTable.COLUMN_CATEGORY + ") REFERENCES " +
CategoriesTable.TABLE_NAME + "(" + QuestionsTable._ID + ")" +
")";
db.execSQL(SQL_CREATE_CATEGORIES_TABLE);
db.execSQL(SQL_CREATE_QUESTIONS_TABLE);
fillCategoriesTable();
fillQuestionsTable();
}
这里我用初始问题填充表格,然后我尝试从类别表中删除一行以故意违反外键约束(以测试它):
private void fillQuestionsTable() {
Question q1 = new Question("Easy: A is correct",
"A", "B", "C", 1, Question.DIFFICULTY_EASY, 1);
addQuestion(q1);
Question q2 = new Question("Medium: B is correct",
"A", "B", "C", 2, Question.DIFFICULTY_MEDIUM, 2);
addQuestion(q2);
Question q3 = new Question("Medium: C is correct",
"A", "B", "C", 3, Question.DIFFICULTY_MEDIUM, 3);
addQuestion(q3);
Question q4 = new Question("Hard: A is correct",
"A", "B", "C", 1, Question.DIFFICULTY_HARD, 4);
addQuestion(q4);
Question q5 = new Question("Hard: B is correct",
"A", "B", "C", 2, Question.DIFFICULTY_HARD, 5);
addQuestion(q5);
Question q6 = new Question("Hard: C is correct",
"A", "B", "C", 3, Question.DIFFICULTY_HARD, 6);
addQuestion(q6);
db.execSQL("DELETE FROM " + CategoriesTable.TABLE_NAME + " WHERE ID = 1");
}
我收到运行时异常。 请注意我是故意违反外键约束而只是想了解异常。
我的第一个问题是:
1)崩溃是因为删除,但为什么logcat只讨论将问题添加到类别4,5和6(首先不在我的类别表中)?
插入难度时出错=硬选项1 =问题=硬:C是正确的category_id = 6 answer_nr = 3 option3 = C option2 = B android.database.sqlite.SQLiteConstraintException:FOREIGN KEY约束失败(代码787)
为什么不像我期望的那样谈论删除引用的列?
2)为什么它会抛出一个运行时异常,而试图添加一个类别在类别表中不存在的问题,只是忽略了SQLite命令,但是不会使应用程序崩溃? 通过尝试删除引用的列来违反外键约束时,运行时异常是预期的行为吗?
答案 0 :(得分:1)
1)崩溃是因为删除,但为什么logcat只能说话 关于将问题添加到类别4,5和6(不在我的 类别表在第一位)?
没有崩溃或者至少显示的消息是因为它表示FOREIGN KEY约束违规,这发生在删除之前(addQuestion(q6);
),因此删除永远不会发生。
解释FOREIGN KEY约束及其失败的原因有点困难,因为看起来你有混合表列。但我的猜测是,这本身不是问题。
更具体地说,您可以使用
定义FOREIGN KEY约束FOREIGN KEY(column_in_this_table_which_you_have_right)
REFERENCES the_other_table_which_you_have_right
(column_in_the_other_table_????)
对于另一个表中的列,您QuestionsTable._ID
应为CategoriesTable._ID
。但是,它们可能被称为相同。所以这不会引起问题。
错误消息包括 category_id = 6
假设他们都解析为ID,那么你实际上是在说
如果** question 表的 category_id *列与中的行匹配(可以引用),则只允许在问题表中插入一行>类别表格 ID 列与 category_id 相同(即6)。
简而言之,显示的消息显示没有ID为6的类别。
为什么不像我那样谈论删除引用的列 期望?
因为它在到达db.execSQL("DELETE FROM " + CategoriesTable.TABLE_NAME + " WHERE ID = 1");
2)为什么它会抛出运行时异常,而试图添加一个 具有类别中不存在的类别的问题 表,只是忽略SQLite命令,但不会使应用程序崩溃?
因为在所有可能性中,您的应用程序将在许多地方崩溃而没有。你说这对设计来说非常重要。我毫不怀疑,如果忽略选项就是这种情况,那么你就会更加相反(即最好的选择,没有人强迫你定义约束)。虽然如果你想要的话,你可以查看4.2 Deferred Foreign Key Constraints
运行时异常是违反外部时的预期行为 尝试删除引用列的键约束?
重申你没有那么远。
但是,您可以查看4.3 ON DELETE and ON UPDATE Actions
简而言之,崩溃实际上是由于DELETE约束,INSERT约束被捕获但显示为正在使用标准insert
方法。如果您仔细查看,日志将显示此信息,如下所述。
以下是基于您汇总的代码的示例: -
04-11 21:47:10.241 1927-1927/? E/SQLiteDatabase: Error inserting option1=A category_id=6 option2=B option3=C difficulty=Hard answer_nr=3 question=Hard: C is correct
android.database.sqlite.SQLiteConstraintException: foreign key constraint failed (code 19)
at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:775)
at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1469)
at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1339)
at askit.questionaire.DatabaseHelper.addQuestion(DatabaseHelper.java:70)
at askit.questionaire.DatabaseHelper.fillQuestionsTable(DatabaseHelper.java:97)
at askit.questionaire.DatabaseHelper.onCreate(DatabaseHelper.java:52)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:252)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
at askit.questionaire.DatabaseHelper.<init>(DatabaseHelper.java:17)
at askit.questionaire.MainActivity.onCreate(MainActivity.java:14)
at android.app.Activity.performCreate(Activity.java:5008)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
04-11 21:47:10.245 1927-1927/? D/AndroidRuntime: Shutting down VM
04-11 21:47:10.245 1927-1927/? W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0xa6294288)
04-11 21:47:10.245 1927-1927/? E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{askit.questionaire/askit.questionaire.MainActivity}: android.database.sqlite.SQLiteConstraintException: foreign key constraint failed (code 19)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.database.sqlite.SQLiteConstraintException: foreign key constraint failed (code 19)
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:727)
at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:754)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1665)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1594)
at askit.questionaire.DatabaseHelper.fillQuestionsTable(DatabaseHelper.java:99)
at askit.questionaire.DatabaseHelper.onCreate(DatabaseHelper.java:52)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:252)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
at askit.questionaire.DatabaseHelper.<init>(DatabaseHelper.java:17)
at askit.questionaire.MainActivity.onCreate(MainActivity.java:14)
at android.app.Activity.performCreate(Activity.java:5008)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
您看到的相当于: -
04-11 21:47:10.241 1927-1927/? E/SQLiteDatabase: Error inserting option1=A category_id=6 option2=B option3=C difficulty=Hard answer_nr=3 question=Hard: C is correct
android.database.sqlite.SQLiteConstraintException: foreign key constraint failed (code 19)
然而,这并不会导致应用程序崩溃。
您需要做的是继续完成日志,您将找到相应的: -
04-11 21:47:10.245 1927-1927/? D/AndroidRuntime: Shutting down VM
04-11 21:47:10.245 1927-1927/? W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0xa6294288)
04-11 21:47:10.245 1927-1927/? E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{askit.questionaire/askit.questionaire.MainActivity}: android.database.sqlite.SQLiteConstraintException: foreign key constraint failed (code 19)
这是崩溃,即 FATAL EXCEPTION:
如果你继续,你会看到由引起的,这是你看的地方所以: -
Caused by: android.database.sqlite.SQLiteConstraintException: foreign key constraint failed (code 19)
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:727)
at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:754)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1665)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1594)
at askit.questionaire.DatabaseHelper.fillQuestionsTable(DatabaseHelper.java:99)
at askit.questionaire.DatabaseHelper.onCreate(DatabaseHelper.java:52)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:252)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
at askit.questionaire.DatabaseHelper.<init>(DatabaseHelper.java:17)
at askit.questionaire.MainActivity.onCreate(MainActivity.java:14)
at android.app.Activity.performCreate(Activity.java:5008)
如果您查看由引起的日志,您会看到提及您的软件包的第一行是: -
at askit.questionaire.DatabaseHelper.fillQuestionsTable(DatabaseHelper.java:99)
第99行(您的行号与包装不同)指向
CategoriesTable._ID
)作为类别ID列。