Accès concurrent à une base de donnée locale
Bonjour,
Je suis actuellement en train de rencontrer un problème sur mon application. Depuis plusieurs threads, l'appli accède à une base de donnée locale afin d'effectuer des enregistrement.
Le problème est qu'il semble impossible de permettre à la base de donnée d'avoir plusieurs accès simultanés.
Je pensais utiliser un objet qui gérerait un thread obligatoire pour l'accès à la BD, avec du coup une file d'attente, mais je n'ai aucune expérience dans ce domaine.
Quelqu'un aurait-il rencontré ce problème?
Je suis actuellement en train de rencontrer un problème sur mon application. Depuis plusieurs threads, l'appli accède à une base de donnée locale afin d'effectuer des enregistrement.
Le problème est qu'il semble impossible de permettre à la base de donnée d'avoir plusieurs accès simultanés.
Je pensais utiliser un objet qui gérerait un thread obligatoire pour l'accès à la BD, avec du coup une file d'attente, mais je n'ai aucune expérience dans ce domaine.
Quelqu'un aurait-il rencontré ce problème?
Mots clés:
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Le plus simple c'est d'utiliser NSOperation pour empiler tes requêtes sur une NSOperationQueue, ou d'utiliser GCD et empiler tes requêtes sur une queue serial. Il te restera quand même quelques subtilités à gérer mais l'idée est là
Comme d'habitude pour tous les problèmes de multithreading je déconseille fortement d'utiliser NSThread, tout comme Apple le déconseille également, il y a tellement de subtilités à gérer avec les API de threading bas niveau de ce type et c'est devenu obsolète avec toutes les nouvelles méthodes pour faire du concurrency programming bien plus efficace que ça serait bête de ce passer de ces nouvelles technos. Je t'invite très très fortement à lire le Concurrency Programming Guide dans la doc Apple qui explique les diverses techniques pour migrer des NSThread vers les nouvelles technos, pourquoi c'est mieux et moins compliqué, et tous les concepts à connaà®tre et à avoir conscience quand on fait du multithreading. Il y a également plusieurs vidéos WWDC sur le sujet qui valent le coup d'être regardées, car le multithreading à bon nombre de subtilités.
Pour ma part pour ma base de données interne de cache j'ai fait un service dédié dans mon appli qui utilise les avantages de GCD pour avoir une file d'attente (type queue GCD avec une toute bête dispatch_queue_t) en postant mes requêtes dessus (dispatch_async) et j'utilise les blocks à fond pour me signaler quand une requête à fini de s'exécuter, par exemple pour me retourner une réponse.
Comme ça tout mon système d'interaction avec ma BDD est thread-safe, asynchrone (non bloquant pour l'UI), et permet d'avoir du code appelant qui reste lisible comme si c'était synchrone (vive les completionBlocks) plutôt que de devoir mettre des delegate partout ou quoi.
Je viens de finir la fin de ton message Ali, je vois qu'on est sur la même longueur d'ondes /tongue.png' class='bbc_emoticon' alt=':P' />. Alors la question clef est : comment j'e réserve une queue juste pour la base de données? je n'ai pas trouvé de ou une méthode du genre.
Edit : j'ai trouvé, pour informations, créer une dispatch_queue_t se fait avec
Si je ne me suis pas trompé /smile.png' class='bbc_emoticon' alt=':)' />
Merci a vous !
Je t'invite à lire le Programming Guide sur GCD qui explique les différents types de queue, les différents concepts de GCD en détail, et comment faire certaines opérations usuelles. Tu y apprendras par exemple pourquoi dans ton cas utiliser dispatch_sync n'est pas une bonne idée (ça va bloquer ton code du main thread jusqu'à l'exécution de ta requête sur ta queue dédiée, rendant le tout synchrone, si tu commences à avoir des requetes qui prennent du temps ou s'entassent dans ta queue ça va geler ton appli jusqu'à leur exécution) et comment faire pour rendre ça asynchrone.
Je te conseille également à nouveau les sessions vidéo WWDC dédiées à GCD qui sont plus qu'instructives comme souvent.
FMDB pourrait peut-être répondre assez facilement à tes attentes.
@Lexxis : j'utilise déjà FMDB. En fait je possède sur l'appli un singleton héritant d'un FMDatabase (je m'y suis peut-être mal pris, mais je trouve cette méthode d'accès plus propre). Le soucis est qu'il fallait que j'accède à ce singleton depuis le même thread, sinon certaines requêtes tentaient de s'effectuer en même temps ce qui générait des erreurs.
Tu peux te faire des méthodes qui fonctionnent un peu de la même manière que toutes ces APIs d'Apple utilisant des "completionBlocks". Donc au lieu de retourner immédiatement une valeur de retour (ce que tu ne peux pas faire conceptuellement puisque tu dois prévoir une API asynchrone), tu appelles un block quand tu as le résultat pour exécuter le reste du code.
C'est plus compliqué à expliquer qu'à faire et à utiliser, vraiment. Et en plus ça te permet de retourner plusieurs valeurs à la fois.
Par exemple si dans ta base tu as une liste de personnes associés à des IDs et que tu veux une méthode que te retourne le nom et le prénom de la personne correspondant à un ID donné, ça donnera : Voilà , en fait à peu de choses près cela revient à remplacer ta méthode qui retourne un objet par une méthode qui ne retourne rien (void) et prend un completionBlock en paramètre... et dans le code de ta méthode, de remplacer le "return" par un appel au completionBlock ! En prenant juste soin de l'appeler sur la queue d'origine et pas sur la dbQueue, mais c'est à peu près tout ce que ça change sinon /smile.png' class='bbc_emoticon' alt=':)' />