2015-11-06 16 views
8

私は、特定のデータのために、次のエラーを取得しています、と概念が十分に明確である:しかしAndroidのSQLiteConstraintExceptionから特定のエラーの詳細を取得することができますか?

android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787)

、私は特定のレコードが無効なFKを持っている見つける助けにはならないこと。私のコードをスラッシュして新しいトランザクションですべてのインサートを分離しようとするのではなく、問題のテーブルや問題を引き起こしているFK値などの役に立つ情報をログに記録する方法はありますか?

また、私は

更新(単に操作をログに記録し、私はまだエラーの詳細情報を取得しないこと)SqlBriteを使用していて、上のデバッグログを有効にしている: はここのすべてです私自身のコードの上にlogcat;以前に開いたトランザクション(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) 
+0

あなたのlogcatの多くを投稿することができ –

+0

私は自分自身の内部コードの上にlogcatのすべてを追加するように更新してください。 – ProjectJourneyman

+0

おそらくsqlも必要です。別のテーブルの参照を持つテーブルからレコードを削除しようとしている可能性があります(またはヌルIDでレコードを削除しようとしていますか?) –

答えて

3

解決方法1:

あなたは、データベースに関するいくつかの情報を見ることがadb shell dumpsys dbinfo -vコマンドを使用することができます。私の場合は

は、私が二度強制的に同じレコードを挿入する小さな例を作成しましたSQLiteConstraintException:これは私のネクサス4でadb shell dumpsys dbinfo -vコマンドの出力(私はわからないが、

MyDB db = new MyDB(this); 

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

ですが、私は、出力情報)はデバイス間で異なることができると思います。

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:で、出力を分析する()1つのレコードが正常に挿入され、別のに失敗しました:

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:

このソリューションは少しトリッキーですが、Javaコードを経由して同様の情報を取得するためにandroid.database.sqlite.SQLiteDebugクラスを使用することができます。

thisを見ると、このクラスは@hideとマークされています。つまり、SQLiteDebugクラスはAPIドキュメントから除外されていますが、リフレクションによってアクセスできます。私が使用してこの場合

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()); 
} 

:ソリューションを説明するため

// 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"}); 

簡単な例:

ので、SQLiteのデータベースのためのデバッグ情報を印刷するには、次のコードを使用することができますデバッグ情報をlogcatにダンプするにはLogPrinterが必要ですが、独自のPrinter実装を使用することができます。私のネクサス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:に(1つのレコードが正常に挿入され、別のに失敗しました):

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"] 

希望します。

+0

私はトランザクションがあり、コミット時にエラーが発生するので、私にとってはまったく同じ動作をしませんが、これはDBコールのログを有効にしていないときに使用するのに適したツールです。私はまだ問題を追跡するためにインサートを別々のトランザクションにスライスアップする必要がありますが、これは私のツールボックスに便利な機能だから賞金を授与します。 – ProjectJourneyman

+0

私は戻って、あなたの方法2を使ってダンプから情報を抽出するロガーを実装しました。いくつかの創造的な正規表現のアクションでは、問題の行をクエリのパラメータで傷つけることができます私はトランザクションを使用しているので*後*の行になると失敗します。私がトランザクションごとに潜在的に面倒なコマンドを分離する限り、これは生産上有用であるように見えます。 – ProjectJourneyman

+0

ソリューションはproducton環境で役立つと聞いてうれしいですが、デバイス間で出力が異なることがある正規表現を使用する場合は考慮してください(少なくとも、テストした2つの異なるデバイスで出力が異なります)。フォローアップありがとうございます。 – antonio

3

take out that SQLite file from your deviceと入力してから、SQLiteブラウザのアプリケーションにロードしてください。つまり、同じトランザクションを実行して何が起こっているのかを見ることができます。

SQLiteのブラウザ:

+1

こんにちは、ありがとう - 私はSQLite Studioを使用し、頻繁にDBをローカルで検査し、やりとりするために使用します。しかし、問題となっているSQLは何百もの行になる可能性があります。私は生産データを調べて、問題のあるものが何であるか把握しています。問題の行を分離するために、すべてのコミットを別々のトランザクションに分割するまでに、私は既に保存しようとしていた作業のほとんどを実行しました.DBのローカルコピーに関するいくつかのクエリが実際に表示されます私はFKが欠けている行を指しています。 – ProjectJourneyman

関連する問題