2011-12-31 6 views
8

Ho un database SQLite in Android e utilizzo uno ContentProvider per gestire le operazioni, che vengono mantenute su una tabella con un qualificatore UNIQUE in una colonna.È corretto fare affidamento su un SQLiteConstraint e lasciare che SQLite esegua il controllo per me? C'è un problema?

Problema:

Tuttavia, quando ho insert valori duplicati nel database, non si rompe il mio codice di per sé, ma sputa ancora migliaia di SQLiteConstraintException linee tronchi, e al mio utente che sembra proprio di inquinare il Log, qualcosa di non lucidato. Ho provato a rilevare l'eccezione solo per sperimentare, ma registra ancora.

Domanda:

Allora, come faccio in silenzio quelle linee di registro? È possibile?

Si prega di leggere il commento qui sotto per il motivo di porre la domanda.

Errore:

colonna Ora ha il UNIQUE vincolo:

Error inserting Factor=2.0 Time=1325375465000 Extra=none 
android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed 
    at android.database.sqlite.SQLiteStatement.native_execute(Native Method) 
    at android.database.sqlite.SQLiteStatement.execute(SQLiteStatement.java:55) 
    at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1549) 
    at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1410) 
    at mypackage.myapp.provider.DataProvider.bulkInsert(DataProvider.java:353) 
    at android.content.ContentProvider$Transport.bulkInsert(ContentProvider.java:179) 
    at android.content.ContentResolver.bulkInsert(ContentResolver.java:646) 
    at mypackage.myapp.service.MyService.onHandleIntent(MyService.java:96) 
    at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:59) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:123) 
    at android.os.HandlerThread.run(HandlerThread.java:60) 
+0

mi sento che tutto questo significa che quello che sto cercando di fare è un modo pigro per recuperare da un inserto duplicato su un vincolo univoco, da qui il "rozzo" sentire nel registro. Probabilmente sto risolvendo meglio qualunque cosa stia creando le voci duplicate (e chiamando gli inserti) per cominciare. Sono tutto per la scorrevolezza. Ma questo solleva la domanda (per me): perché non possiamo semplicemente "scaricare" in sicurezza il lavoro sul correttore dei vincoli e lasciarlo fallire log-silenziosamente? Nel caso volessimo ... forse ci aspettiamo duplicati ... quindi niente di cui preoccuparsi. Forse la nostra fonte di dati, fuori dal nostro controllo, è difettosa per cominciare con ... – davidcesarino

+0

Commentare dopo aver risposto: come ho detto, ero pigro di proposito, ai fini di questa domanda, poiché stavo cercando di non codificare gli assegni e lascialo a SQLite chiedendo 1) sicurezza (concorrenza), 2) efficienza (è sqlite migliore/più veloce di me su quello? probabilmente) e anche 3) praticamente (meno codice). Tuttavia, alcune cose mi sono venute in mente (il conteggio delle righe di inserimento), quindi ho implementato il controllo dups oltre ai limiti. Ad ogni modo, sono finito molto soddisfatto del mio codice riguardante (1). Ricorda questo quando leggi questa domanda. – davidcesarino

+0

Se non si sta utilizzando android.util.Log autonomamente, allora perché si preoccupa di registrare errori per l'utente? –

risposta

10

Se è possibile formulare o modificare il codice SQL da soli, sia per INSERT o per l'iniziale CREATE TABLE, è possibile utilizzare SQLite's conflict handling extensions. Ci sono due opzioni per come fare questo:

  • Quando si inserisce, utilizzare INSERT OR IGNORE piuttosto che solo INSERT. Puoi anche utilizzare OR REPLACE, OR ABORT o una qualsiasi di molte altre reazioni.
  • Quando si crea la tabella, specificare una clausola ON CONFLICT IGNORE per il vincolo UNIQUE. Ciò farà sì che inserti o aggiornamenti che violano il vincolo non facciano silenziosamente nulla.

trovo l'idea di utilizzare INSERT OR IGNORE/INSERT OR REPLACE per gestire i dati duplicati, in particolare in ambienti contemporanei, di essere molto pulito. Controlla la duplicazione una volta - nel database - ed evita le condizioni di gara in cui si controlla prima l'esistenza (certamente non un problema se solo un processo/thread accede al database).

Tuttavia, se i duplicati sono il risultato di un errore (piuttosto che duplicare eventi/azioni che il codice non è semplicemente deduplicare), questo potrebbe semplicemente nascondere il bug anziché risolverlo. La mancanza di de-dulicazione esplicita, tuttavia, non è un bug secondo me. Quindi se la correzione è per verificare la presenza di duplicati, utilizzare il database; se il vero problema è che sono stati generati in primo luogo (al livello di applicazione effettivo, non al livello di riga del database), probabilmente dovrei cercare il problema.

+2

Grazie, questo è esattamente quello che avevo in mente. Ho anche notato che se uso 'ON CONFLICT IGNORE' sullo schema della tabella,' SQLiteDatabase.insert (String, String, ContentValues) di Android 'riporterà la riga come inserita ... quindi fai attenzione se ti serve. E sì, considerando che ho molti servizi che scaricano materiale, ha anche il vantaggio di evitare le condizioni di gara. Grazie. – davidcesarino

1

Sì, puoi lasciarlo e come dici tu potresti aggiustarlo. A mio avviso, dipende dal fatto che i duplicati siano eventi eccezionali o "semplicemente capita perché sei pigro".

Penso che in generale costi meno pulire i dati all'ingresso di un modulo piuttosto che occuparsene successivamente. Tuttavia, il modo in cui definisci il costo dipende da te.

+0

La maggior parte dei duplicati non lo sono, ma alcuni potrebbero essere risolti da me prima ancora di attivare il downloader del servizio. Sono d'accordo sul controllo al punto di ingresso. Tuttavia, sono lontano dal finire il codice, e lo stavo chiedendo anche in una prospettiva "what-if". – davidcesarino

4

Usa SQLiteDatabase.insertOrThrow(...)