2009-06-08 8 views
9

Quelqu'un peut-il fournir des informations sur cette erreur? J'essaie d'insérer dans la table en utilisant Objective C.Exception SQLite: SQLite Occupé

Pendant que je fais ceci, j'obtiens une erreur SQLite Busy. Pourquoi cela se passe-t-il?

+0

pouvez-vous fournir un exemple de code? Deux lignes pour comprendre ce qui se passe. – stefanB

Répondre

19

Si vous obtenez comme résultat lors de l'appel d'une fonction sqlite3 le code d'erreur SQLITE_BUSY, cela signifie comme observé par drdaeman que le db a été verrouillé par le même processus ou par un thread dans votre processus. La meilleure façon de gérer cette situation est d'essayer l'opération dans une boucle, et si le code de retour est toujours SQLITE_BUSY, d'attendre un certain temps (vous décidez de la valeur du délai d'attente), puis réessayez l'opération dans le suivant boucle d'itération.

Par exemple, l'extrait de code suivant est extrait de l'emballage Objectif C FMDB (http://code.google.com/p/flycode/source/browse/trunk/fmdb) montre comment préparer une déclaration pour une requête en tenant compte du fait que certaines opérations peuvent 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); 
} 

Par Bien sûr, si vous avez besoin d'accéder à sqlite, FMDB est très pratique et beaucoup plus simple à utiliser en ce qui concerne l'accès direct via les API C natives.

+6

Vous pouvez accomplir à peu près la même chose en appelant simplement [sqlite3_busy_timeout] (http://www.sqlite.org/c3ref/busy_timeout.html). –

+1

Réduit. Premièrement, si quelqu'un fait quelque chose, même dans un projet open-source, cela n'implique pas que ce soit une «bonne chose». Une chose vraiment appropriée est quelque chose d'énoncé dans la documentation par les auteurs de la bibliothèque en question. http://www.sqlite.org/c3ref/busy_handler.html –

+0

@Alaksiej N: avez-vous lu attentivement la documentation du gestionnaire occupé que vous avez fournie dans votre commentaire? Il lit: "La présence d'un gestionnaire occupé ne garantit pas qu'il sera invoqué en cas de conflit de verrous.Si SQLite détermine qu'appeler le gestionnaire occupé peut entraîner un blocage, il ira de l'avant et retournera SQLITE_BUSY ou SQLITE_IOERR_BLOCKED au lieu d'invoquer le gestionnaire occupé. " Par conséquent, il n'y a aucune garantie que SQLite invoquera toujours le gestionnaire occupé que vous définissez! –

7

J'ai rencontré un problème similaire avec SQLITE_BUSY sur les commandes INSERT INTO séquentielles. La première ligne a été insérée correctement, mais lorsque l'application a tenté d'insérer une deuxième ligne, j'ai obtenu le statut SQLITE_BUSY. Après Google, j'ai appris que vous devez appeler sqlite3_finalize() sur les instructions après les avoir exécutées: http://www.sqlite.org/c3ref/finalize.html. La finalisation de mes déclarations a résolu mon problème.

4

Dans mon cas, j'avais oublié de fermer la base de données après l'avoir utilisée. Suite à la mine fixe:

sqlite3_finalize(statement); 
sqlite3_close(contactDB); 

FMDB peut aussi soulager ces maux de tête vous facilement.

0

C'était aussi simple que de lancer l'invite de commande en tant qu'administrateur pour moi. Alternativement sous UNIX, vous pouvez utiliser sudo lors du démarrage de la base de données.