Можно ли получить конкретные сведения об ошибке из Android SQLiteConstraintException?

Я получаю следующую ошибку для определенных данных, и концепция достаточно ясна:

  Android.database.sqlite.SQLiteConstraintException: ограничение FOREIGN KEY не выполнено (код 787) 

Однако это не помогает мне определить, какая конкретная запись имеет недопустимый FK. Вместо того, чтобы разбивать мой код и пытаться изолировать каждую вставку с помощью новой транзакции, есть ли способ включить (или извлечь) журнал с полезными подробностями, такими как рассматриваемая таблица или даже значение FK, вызывающее проблемы?

Кроме того, я использую SqlBrite и включил ведение журнала отладки (который только регистрирует операции, я до сих пор не получаю больше информации об ошибке)

Обновление: вот весь лог-код выше моего собственного кода; По сути, исключение поймано при попытке закрыть транзакцию (BriteDatabase.Transaction), ранее открытую (объект BriteDatabase.Transaction является новым дополнением, я просто перенесен из SqlBrite 0.1.0 в 0.4.1).

android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787) at android.database.sqlite.SQLiteConnection.nativeExecute(Native Method) at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:555) at android.database.sqlite.SQLiteSession.endTransactionUnchecked(SQLiteSession.java:437) at android.database.sqlite.SQLiteSession.endTransaction(SQLiteSession.java:401) at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:522) at com.squareup.sqlbrite.BriteDatabase$1.end(BriteDatabase.java:85) 

    Решение 1:

    Вы можете использовать команду adb shell dumpsys dbinfo -v чтобы просмотреть некоторую информацию о базах данных.

    В моем случае я создал небольшой пример, который вставляет одну и ту же запись, дважды заставляя SQLiteConstraintException :

     MyDB db = new MyDB(this); // Insert the same record twice to force a SQLiteConstraintException db.insertIntoMyTable("1","MyName"); db.insertIntoMyTable("1","MyName"); 

    Это вывод команды adb shell dumpsys dbinfo -v в моем Nexus 4 (я не уверен, но я думаю, что информация о выходе может различаться между устройствами):

     Connection pool for /data/data/com.your.package.name/databases/MyDB: Open: true Max connections: 1 Available primary connection: Connection #0: connectionPtr: 0xffffffffb883aaf0 isPrimaryConnection: true onlyAllowReadOnlyOperations: false Most recently executed operations: 0: [2015-11-13 17:59:16.227] executeForLastInsertedRowId took 1ms - failed, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)", bindArgs=["MyName", "1"], exception="UNIQUE constraint failed: MyTable._id (code 1555)" 1: [2015-11-13 17:59:16.227] prepare took 0ms - succeeded, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)" 2: [2015-11-13 17:59:16.209] executeForLastInsertedRowId took 18ms - succeeded, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)", bindArgs=["MyName", "1"] 3: [2015-11-13 17:59:16.209] prepare took 0ms - succeeded, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)" 4: [2015-11-13 17:59:16.208] executeForLong took 1ms - succeeded, sql="PRAGMA user_version;" 5: [2015-11-13 17:59:16.208] prepare took 0ms - succeeded, sql="PRAGMA user_version;" 6: [2015-11-13 17:59:16.208] executeForString took 0ms - succeeded, sql="SELECT locale FROM android_metadata UNION SELECT NULL ORDER BY locale DESC LIMIT 1" 7: [2015-11-13 17:59:16.207] execute took 1ms - succeeded, sql="CREATE TABLE IF NOT EXISTS android_metadata (locale TEXT)" 8: [2015-11-13 17:59:16.207] executeForLong took 0ms - succeeded, sql="PRAGMA wal_autocheckpoint=100" 9: [2015-11-13 17:59:16.207] executeForLong took 0ms - succeeded, sql="PRAGMA wal_autocheckpoint" 10: [2015-11-13 17:59:16.207] executeForLong took 0ms - succeeded, sql="PRAGMA journal_size_limit=524288" 11: [2015-11-13 17:59:16.207] executeForLong took 0ms - succeeded, sql="PRAGMA journal_size_limit" 12: [2015-11-13 17:59:16.206] executeForString took 0ms - succeeded, sql="PRAGMA synchronous" 13: [2015-11-13 17:59:16.206] executeForString took 0ms - succeeded, sql="PRAGMA journal_mode=PERSIST" 14: [2015-11-13 17:59:16.205] executeForString took 1ms - succeeded, sql="PRAGMA journal_mode" 15: [2015-11-13 17:59:16.204] executeForLong took 0ms - succeeded, sql="PRAGMA foreign_keys" 16: [2015-11-13 17:59:16.204] executeForLong took 0ms - succeeded, sql="PRAGMA page_size" Prepared statement cache: 0: statementPtr=0xffffffffb8839558, numParameters=0, type=1, readOnly=true, sql="SELECT locale FROM android_metadata UNION SELECT NULL ORDER BY locale DESC LIMIT 1" Available non-primary connections: <none> Acquired connections: <none> Connection waiters: <none> 

    Анализируя вывод, в Most recently executed operations: я получаю следующую информацию (одна запись успешно вставлена, а другая не удалась):

     0: [2015-11-13 17:59:16.227] executeForLastInsertedRowId took 1ms - failed, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)", bindArgs=["MyName", "1"], exception="UNIQUE constraint failed: MyTable._id (code 1555)" 2: [2015-11-13 17:59:16.209] executeForLastInsertedRowId took 18ms - succeeded, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)", bindArgs=["MyName", "1"] 

    Решение 2:

    Это решение немного сложно, но вы можете использовать класс android.database.sqlite.SQLiteDebug для получения подобной информации через код Java.

    Если вы посмотрите на это, вы увидите, что этот класс отмечен как @hide что означает, что класс SQLiteDebug исключен из документов API, но к нему по-прежнему можно получить доступ через отражение.

    Итак, чтобы распечатать информацию об отладке для баз данных SQLite, вы можете использовать следующий код:

     // The messages will be printed as Log.ERROR using the tag "DB" Printer p = new LogPrinter(Log.ERROR, "DB"); // We will invoke the "dump" method of the "android.database.sqlite.SQLiteDebug" class // We eill use the "-v" parameter because we want the output to be verbose Class<?> c = Class.forName("android.database.sqlite.SQLiteDebug"); Method method = c.getMethod("dump", new Class[]{Printer.class, String[].class}); method.invoke(null, p, new String[]{"-v"}); 

    Простой пример для иллюстрации решения:

     MyDB db = new MyDB(this); // Insert the same record twice to force a SQLiteConstraintException db.insertIntoMyTable("1","MyName"); db.insertIntoMyTable("1","MyName"); try { Printer p = new LogPrinter(Log.ERROR, "DB"); Class<?> c = Class.forName("android.database.sqlite.SQLiteDebug"); Method method = c.getMethod("dump", new Class[]{Printer.class, String[].class}); method.invoke(null, p, new String[]{"-v"}); } catch (Exception e) { Log.e("MyTag", e.getMessage()); } 

    В этом случае я использую LogPrinter для LogPrinter информации об отладке в logcat, но вы можете использовать собственную реализацию Printer .

    В моем Nexus 4 logcat выглядит так (я не уверен, но я думаю, что информация о выходе может различаться между устройствами):

     E/SQLiteLog(22296): (1555) abort at 10 in [INSERT INTO MyTable(name,_id) VALUES (?,?)]: UNIQUE constraint failed: MyTable._id E/SQLiteDatabase(22296): Error inserting name=MyName _id=1 E/SQLiteDatabase(22296): android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: MyTable._id (code 1555) E/SQLiteDatabase(22296): at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method) E/SQLiteDatabase(22296): at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:782) E/SQLiteDatabase(22296): at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788) E/SQLiteDatabase(22296): at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86) E/SQLiteDatabase(22296): at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1471) E/SQLiteDatabase(22296): at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1341) E/SQLiteDatabase(22296): at com.example.antonio.prueba3.MyDB.insertIntoMyTable(MyDB.java:32) E/SQLiteDatabase(22296): at com.example.antonio.prueba3.MainActivity.onCreate(MainActivity.java:24) E/SQLiteDatabase(22296): at android.app.Activity.performCreate(Activity.java:5990) E/SQLiteDatabase(22296): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106) E/SQLiteDatabase(22296): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278) E/SQLiteDatabase(22296): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) E/SQLiteDatabase(22296): at android.app.ActivityThread.access$800(ActivityThread.java:151) E/SQLiteDatabase(22296): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) E/SQLiteDatabase(22296): at android.os.Handler.dispatchMessage(Handler.java:102) E/SQLiteDatabase(22296): at android.os.Looper.loop(Looper.java:135) E/SQLiteDatabase(22296): at android.app.ActivityThread.main(ActivityThread.java:5254) E/SQLiteDatabase(22296): at java.lang.reflect.Method.invoke(Native Method) E/SQLiteDatabase(22296): at java.lang.reflect.Method.invoke(Method.java:372) E/SQLiteDatabase(22296): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) E/SQLiteDatabase(22296): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) E/DB (22296): Connection pool for /data/data/com.example.antonio.prueba3/databases/MyDB: E/DB (22296): Open: true E/DB (22296): Max connections: 1 E/DB (22296): Available primary connection: E/DB (22296): Connection #0: E/DB (22296): connectionPtr: 0xffffffffb883aaf0 E/DB (22296): isPrimaryConnection: true E/DB (22296): onlyAllowReadOnlyOperations: false E/DB (22296): Most recently executed operations: E/DB (22296): 0: [2015-11-13 17:59:16.227] executeForLastInsertedRowId took 1ms - failed, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)", bindArgs=["MyName", "1"], exception="UNIQUE constraint failed: MyTable._id (code 1555)" E/DB (22296): 1: [2015-11-13 17:59:16.227] prepare took 0ms - succeeded, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)" E/DB (22296): 2: [2015-11-13 17:59:16.209] executeForLastInsertedRowId took 18ms - succeeded, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)", bindArgs=["MyName", "1"] E/DB (22296): 3: [2015-11-13 17:59:16.209] prepare took 0ms - succeeded, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)" E/DB (22296): 4: [2015-11-13 17:59:16.208] executeForLong took 1ms - succeeded, sql="PRAGMA user_version;" E/DB (22296): 5: [2015-11-13 17:59:16.208] prepare took 0ms - succeeded, sql="PRAGMA user_version;" E/DB (22296): 6: [2015-11-13 17:59:16.208] executeForString took 0ms - succeeded, sql="SELECT locale FROM android_metadata UNION SELECT NULL ORDER BY locale DESC LIMIT 1" E/DB (22296): 7: [2015-11-13 17:59:16.207] execute took 1ms - succeeded, sql="CREATE TABLE IF NOT EXISTS android_metadata (locale TEXT)" E/DB (22296): 8: [2015-11-13 17:59:16.207] executeForLong took 0ms - succeeded, sql="PRAGMA wal_autocheckpoint=100" E/DB (22296): 9: [2015-11-13 17:59:16.207] executeForLong took 0ms - succeeded, sql="PRAGMA wal_autocheckpoint" E/DB (22296): 10: [2015-11-13 17:59:16.207] executeForLong took 0ms - succeeded, sql="PRAGMA journal_size_limit=524288" E/DB (22296): 11: [2015-11-13 17:59:16.207] executeForLong took 0ms - succeeded, sql="PRAGMA journal_size_limit" E/DB (22296): 12: [2015-11-13 17:59:16.206] executeForString took 0ms - succeeded, sql="PRAGMA synchronous" E/DB (22296): 13: [2015-11-13 17:59:16.206] executeForString took 0ms - succeeded, sql="PRAGMA journal_mode=PERSIST" E/DB (22296): 14: [2015-11-13 17:59:16.205] executeForString took 1ms - succeeded, sql="PRAGMA journal_mode" E/DB (22296): 15: [2015-11-13 17:59:16.204] executeForLong took 0ms - succeeded, sql="PRAGMA foreign_keys" E/DB (22296): 16: [2015-11-13 17:59:16.204] executeForLong took 0ms - succeeded, sql="PRAGMA page_size" E/DB (22296): Prepared statement cache: E/DB (22296): 0: statementPtr=0xffffffffb8839558, numParameters=0, type=1, readOnly=true, sql="SELECT locale FROM android_metadata UNION SELECT NULL ORDER BY locale DESC LIMIT 1" E/DB (22296): Available non-primary connections: E/DB (22296): <none> E/DB (22296): Acquired connections: E/DB (22296): <none> E/DB (22296): Connection waiters: E/DB (22296): <none> 

    Анализируя вывод, я получаю SQLiteConstraintException :

     E/SQLiteDatabase(22296): android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: MyTable._id (code 1555) 

    И в Most recently executed operations: я получаю следующую информацию (одна запись успешно вставлена, а другая не выполнена):

     E/DB (22296): 0: [2015-11-13 17:59:16.227] executeForLastInsertedRowId took 1ms - failed, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)", bindArgs=["MyName", "1"], exception="UNIQUE constraint failed: MyTable._id (code 1555)" E/DB (22296): 2: [2015-11-13 17:59:16.209] executeForLastInsertedRowId took 18ms - succeeded, sql="INSERT INTO MyTable(name,_id) VALUES (?,?)", bindArgs=["MyName", "1"] 

    Надеюсь, поможет.

    Просто вы можете вынуть этот файл SQLite с вашего устройства, а затем загрузить его в приложение-приложение SQLite. Итак, теперь вы можете попытаться выполнить ту же транзакцию и посмотреть, что происходит.

    Браузеры SQLite:

    • Браузер SQLite
    • Менеджер SQLite
    • SQLite Studio
    Intereting Posts
    Получить количество установленных приложений на устройстве Android? Как я могу передать Touch Listeners в пользовательский вид для перетаскивания? Идентификация, когда вид действительно появляется / исчезает из видимой области действия Android + Sencha Touch текстовый ввод дублируется и трудно разобрать Wakelock и wifilock не работают Почему getCount в адаптере вызывается так много раз? Масштабирование холста в SurfaceView до размера, большего, чем размер экрана Как изменить положение кнопки ручки джойстика Требуется версия Gradle 2.2. Текущая версия 2.10 Как отправить смс на мое виртуальное устройство Genymotion? Чтение файла из внешнего хранилища Android SDK Emulator Как остановить Gradle для Android из Building * Все * Типы модулей библиотеки библиотеки на каждой сборке? Телефонная геолокация не работает Активность Android просочилась Каков наилучший способ подождать установки GPS-местоположения?