54 votes

Comment utiliser SQLite dans une application multi-thread?

Je suis du développement d'une application avec SQLite comme base de données, et j'ai un peu de mal à comprendre comment l'utiliser dans plusieurs threads (aucun des autres Débordement de Pile questions m'a vraiment aidé, malheureusement).

Mon cas d'utilisation: La base de données a une table, appelons-la "Une", qui a différents groupes de lignes (basé sur l'une de leurs colonnes). J'ai le "fil conducteur" de l'application qui lit le contenu de la table A. En outre, je décide, une fois dans un certain temps, de mettre à jour un certain groupe de lignes. Pour ce faire, je veux lancer un nouveau thread, supprimer toutes les lignes du groupe, et insérez-la à nouveau (c'est la seule façon de le faire dans le cadre de mon application). Cela peut se produire à différents groupes dans le même temps, j'ai 2+ threads essayer de mettre à jour la base de données.

Je suis à l'aide de différentes transactions de chaque thread, I. E. au début de chaque thread du cycle de mise à jour, j'ai commencer. En fait, ce que chaque thread ne fait appeler "COMMENCER", supprimer de la base de données de toutes les lignes qu'il doit "mettre à jour", et les insère à nouveau avec les nouvelles valeurs (ce qui est la façon dont il doit être fait dans le contexte de ma demande).

Maintenant, j'essaie de comprendre comment je vais sur la mise en œuvre de cette. J'ai essayé de lecture autour (d'autres réponses sur Stack Overflow, l'SQLite site), mais je n'ai pas trouvé toutes les réponses. Voici quelques choses que je me demandais:

  1. Dois-je appeler à "ouvrir" et créer un nouveau sqlite structure de chaque thread?
  2. Dois-je besoin d'ajouter un code spécial pour tout cela, ou est-ce suffisant pour frayer les différents threads, mettre à jour les lignes, et c'est très bien (depuis que je suis en utilisant différentes transactions)?
  3. J'ai vu quelque chose de parler des différents types de verrou il y a, et le fait que je pourrais recevoir "SQLite occupé" à partir de l'appel de certaines Api, mais honnêtement, je ne vois pas de référence qui a complètement expliqué quand j'ai besoin de prendre tout cela en compte. Dois-je?

Si quelqu'un peut répondre aux questions/me pointer dans la direction d'une bonne ressource, je lui en serais très reconnaissant.

Mise à JOUR 1: De tout ce que j'ai lu jusqu'à présent, il semble que vous ne pouvez pas avoir les deux fils qui vont écrire dans un fichier de base de données, de toute façon.

Voir: http://www.sqlite.org/lockingv3.html. Dans la section 3.0: UNE RÉSERVÉE verrou signifie que le processus de planification sur l'écriture pour le fichier de base de données à un certain moment dans l'avenir, mais qu'il est actuellement, il suffit de lire à partir du fichier. Un seul RÉSERVÉS serrure peut être active à la fois, même si plusieurs verrous PARTAGÉS peuvent coexister avec un seul RÉSERVÉS serrure.

Est-ce à dire que je peux aussi bien que spawn hors un seul thread à la mise à jour d'un groupe de lignes à chaque fois? I. e., avoir une sorte de poller thread qui décide que j'ai besoin de mettre à jour certaines des lignes, puis crée un nouveau thread pour le faire, mais jamais plus d'un à la fois? Depuis, il ressemble à n'importe quelle autre thread, j'ai créer ne SQLITE_BUSY jusqu'à ce que le premier thread de finitions, de toute façon.

Ai-je bien compris les choses correctement?

BTW, merci pour les réponses jusqu'à présent, ils ont aidé beaucoup.

30voto

Snazzer Points 2688

Certaines étapes du démarrage avec SQLlite pour multithread utilisation:

  1. Assurez-vous que sqlite est compilé avec le multi threaded drapeau.
  2. Vous devez appeler ouvrir votre fichier sqlite pour créer une connexion sur chaque fil, ne pas partager les connexions entre les threads.
  3. SQLite est un très conservateur modèle de thread, lorsque vous effectuez une opération d'écriture, qui comprend l'ouverture des transactions qui sont sur le point de faire un INSERT/UPDATE/DELETE, les autres threads seront bloqués jusqu'à ce que cette opération est terminée.
  4. Si vous n'utilisez pas une transaction, les transactions sont implicites, donc si vous commencez un INSERT/DELETE/UPDATE, sqlite va essayer d'acquérir un verrou exclusif, et terminer l'opération avant de le relâcher.
  5. Si vous ne BEGIN déclaration EXCLUSIVE, elle fera l'acquisition d'un verrou exclusif avant de faire des opérations dans le cadre de l'opération. Un COMMIT ou ROLLBACK va libérer le verrou.
  6. Votre sqlite3_step, sqlite3_prepare et quelques autres appels peuvent retourner SQLITE_BUSY ou SQLITE_LOCKED. SQLITE_BUSY signifie généralement que sqlite doit acquérir le verrou. La plus grande différence entre les deux valeurs de retour:
    • SQLITE_LOCKED: si vous obtenez ce à partir d'un sqlite3_step déclaration, vous DEVEZ appeler sqlite3_reset sur le descripteur d'instruction. Vous devez seulement obtenir ce sur le premier appel à sqlite3_step, donc une fois que la réinitialisation est appelée, vous pouvez réellement "retry" votre sqlite3_step appel. Sur les autres opérations, il est le même que SQLITE_BUSY
    • SQLITE_BUSY : Il n'est pas nécessaire d'appeler sqlite3_reset, juste recommencez l'opération après avoir attendu un peu pour la libération du verrou.

25voto

Kristian Points 2705

Consultez ce lien. Le plus simple est de faire le verrouillage de vous-même, et d'éviter de partager la connexion entre les threads. Une autre bonne ressource peut être trouvé ici, et il conclut avec:

  1. Assurez-vous que vous êtes à la compilation de SQLite avec -DTHREADSAFE=1.

  2. Assurez-vous que chaque thread ouvre le fichier de base de données et conserve sa propre sqlite structure.

  3. Assurez-vous de gérer le probable qu'un ou plusieurs threads en collision lors de l'accès à la db fichier en même temps: la poignée de SQLITE_BUSY de façon appropriée.

  4. Assurez-vous de placer à l'intérieur de transactions les commandes qui modifient le fichier de base de données, comme INSERT, UPDATE, DELETE, et d'autres.

11voto

adechiaro Points 61

Je me rends compte que c'est un vieux fil et les réponses sont bonnes, mais j'ai étudié cela récemment et suis tombé sur une analyse intéressante de différentes implémentations. Il passe principalement en revue les forces et les faiblesses du partage de connexion, du passage de messages, des connexions thread-local et du pool de connexions. Jetez-y un œil ici: http://dev.yorhel.nl/doc/sqlaccess

3voto

Macarse Points 36519

Vérifiez ce code sur le wiki SQLite .

J'ai fait quelque chose de similaire avec C et j'ai téléchargé le code ici .

J'espère que c'est utile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X