2009-06-08 9 views
9

Qualcuno può fornire qualsiasi input su questo errore. Sto cercando di inserire nella tabella utilizzando l'obiettivo C.SQLite Eccezione: SQLite Occupato

Mentre eseguo ciò, viene visualizzato un errore SQLite Occupato. Perché questo sta accadendo?

+0

puoi fornire qualche codice di esempio? Un paio di righe per capire cosa sta succedendo. – stefanB

risposta

19

Se si ottiene come risultato quando si invoca una funzione sqlite3 il codice di errore SQLITE_BUSY, questo significa che come osservato da drdaeman che il db è stato bloccato dallo stesso processo o da un thread all'interno del vostro processo.

Il modo corretto per affrontare questa situazione è quello di provare l'operazione in un ciclo, e se il codice di ritorno è ancora SQLITE_BUSY, attendere per qualche tempo (si decide il valore di timeout) e quindi ripetere l'operazione nel prossimo loop iterazione.

Per esempio, il seguente frammento di codice è tratto dal FMDB Objective C involucro (http://code.google.com/p/flycode/source/browse/trunk/fmdb) mostra come preparare una dichiarazione per una query tenendo conto che alcune operazioni possono restituire SQLITE_BUSY:

int numberOfRetries = 0; 
BOOL retry   = NO; 

if (!pStmt) { 
    do { 
     retry = NO; 
     rc  = sqlite3_prepare(db, [sql UTF8String], -1, &pStmt, 0); 

     if (SQLITE_BUSY == rc) { 
      retry = YES; 
      usleep(20); 

      if (busyRetryTimeout && (numberOfRetries++ > busyRetryTimeout)) { 
       NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [self databasePath]); 
       NSLog(@"Database busy"); 
       sqlite3_finalize(pStmt); 
       [self setInUse:NO]; 
       return nil; 
      } 
     } 
     else if (SQLITE_OK != rc) { 


      if (logsErrors) { 
       NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); 
       NSLog(@"DB Query: %@", sql); 
       if (crashOnErrors) { 

        NSAssert2(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); 
       } 
      } 

      sqlite3_finalize(pStmt); 

      [self setInUse:NO]; 
      return nil; 
     } 
    } 
    while (retry); 
} 

A modo, se hai bisogno di accedere a sqlite, FMDB è molto pratico e molto più semplice da usare rispetto all'accesso diretto attraverso le API C native.

+6

È possibile ottenere praticamente la stessa cosa semplicemente chiamando [sqlite3_busy_timeout] (http://www.sqlite.org/c3ref/busy_timeout.html). –

+1

Downvoted. Primo, se qualcuno sta facendo una cosa, anche in un progetto open source, non implica che sia una "cosa giusta". Una cosa veramente appropriata è qualcosa che viene indicato nella documentazione dagli autori della biblioteca in questione. http://www.sqlite.org/c3ref/busy_handler.html –

+0

@Alaksiej N: hai letto attentamente la documentazione per il gestore occupato che hai fornito nel tuo commento? Viene visualizzato quanto segue: "La presenza di un gestore occupato non garantisce che verrà richiamata in caso di conflitto di blocco. Se SQLite determina che il richiamo del gestore occupato può provocare un deadlock, continuerà a restituire SQLITE_BUSY o SQLITE_IOERR_BLOCKED anziché richiamare l'operatore impegnato. " Pertanto, non vi è alcuna garanzia che SQLite invocherà sempre il gestore occupato che si definisce! –

7

Ho avuto un problema simile con SQLITE_BUSY su comandi INSERT INTO sequenziali. La prima riga è stata inserita correttamente, ma quando l'app ha provato a inserire una seconda riga, ho ottenuto lo stato SQLITE_BUSY. Dopo aver fatto il giro di Google, ho appreso che devi chiamare sqlite3_finalize() sulle istruzioni dopo averle eseguite: http://www.sqlite.org/c3ref/finalize.html. La conclusione delle mie affermazioni ha risolto il mio problema.

4

Nel mio caso, avevo dimenticato di chiudere il database dopo averlo utilizzato. Dopo la mia fissa:

sqlite3_finalize(statement); 
sqlite3_close(contactDB); 

FMDB può anche alleviare questi mal di testa da voi facilmente.

0

Era semplice come eseguire prompt dei comandi come amministratore per me. In alternativa su UNIX potresti essere in grado di utilizzare sudo all'avvio del database.