Je développe une application avec SQLite en tant que base de données et j'ai un peu de difficulté à comprendre comment l'utiliser pour l'utiliser dans plusieurs threads (aucune des autres questions de Stack Overflow ne m'a vraiment aidée, malheureusement).
Mon cas d'utilisation: La base de données a une table, appelons-la "A", qui contient différents groupes de lignes (basées sur l'une de leurs colonnes). J'ai le "fil principal" de l'application qui lit le contenu de la table A. En outre, je décide de temps en temps de mettre à jour un certain groupe de lignes. Pour ce faire, je veux créer un nouveau thread, supprimer toutes les lignes du groupe et les réinsérer (c'est la seule façon de le faire dans le contexte de mon application). Cela peut arriver à différents groupes en même temps, donc je pourrais avoir 2+ threads essayant de mettre à jour la base de données.
J'utilise différentes transactions de chaque fil, I.E. au début du cycle de mise à jour de chaque thread, j'ai un début. En fait, chaque thread appelle en fait "BEGIN", supprime de la base de données toutes les lignes nécessaires pour "mettre à jour" et les insère à nouveau avec les nouvelles valeurs (c’est ainsi que cela doit être fait dans le contexte de mon script. application).
Maintenant, j'essaie de comprendre comment je vais mettre en œuvre cela. J'ai essayé de lire (autres réponses sur Stack Overflow, le site SQLite) mais je n'ai pas trouvé toutes les réponses. Voici quelques points sur lesquels je m'interroge:
Si quelqu'un peut répondre aux questions/me diriger vers une bonne ressource, je vous en serais très reconnaissant.
UPDATE 1: D'après tout ce que j'ai lu jusqu'à présent, il semble que vous ne pouvez pas avoir deux threads 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: Un verrou RÉSERVÉ signifie que le processus envisage d'écrire dans le fichier de base de données à l'avenir, mais qu'il ne fait actuellement que lire le fichier. Un seul verrou RÉSERVÉ peut être actif à la fois, bien que plusieurs verrous SHARED puissent coexister avec un seul verrou RÉSERVÉ.
Est-ce que cela signifie que je peux aussi bien ne générer qu'un seul thread pour mettre à jour un groupe de lignes à chaque fois? C'est-à-dire qu'il existe un type de thread d'interrogation qui décide que je dois mettre à jour certaines des lignes, puis crée un nouveau thread pour le faire, mais jamais plus d'un à la fois? Comme il ressemble à n'importe quel autre thread que je crée, SQLITE_BUSY sera récupéré jusqu'à la fin du premier thread.
Ai-je bien compris les choses?
BTW, merci pour les réponses jusqu'à présent, ils ont beaucoup aidé.
Découvrez ce lien . Le moyen le plus simple consiste à verrouiller vous-même et à éviter de partager la connexion entre les threads. Une autre bonne ressource peut être trouvée ici , et se termine par:
Assurez-vous de compiler SQLite avec -DTHREADSAFE = 1.
Assurez-vous que chaque thread ouvre le fichier de base de données et conserve sa propre structure SQLite.
Assurez-vous de gérer la possibilité probable de collision entre un ou plusieurs threads lorsqu'ils accèdent simultanément au fichier db: gérez SQLITE_BUSY de manière appropriée.
Veillez à inclure dans les transactions les commandes qui modifient le fichier de base de données, telles que INSERT, UPDATE, DELETE, etc.
Quelques étapes lors du démarrage avec SQLlite pour une utilisation multithread:
Je me rends compte que c’est un vieux fil et que les réponses sont bonnes, mais j’ai étudié la question récemment et suis tombé sur une analyse intéressante de différentes implémentations. Il aborde principalement les points forts et les points faibles du partage de connexion, de la transmission de messages, des connexions thread-locales et du pooling de connexions. Jetez un coup d'oeil ici: http://dev.yorhel.nl/doc/sqlaccess
Vérifiez ce code depuis 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.
La sécurité des threads est activée par défaut dans les versions modernes de SQLite. SQLITE_THREADSAFE
compilation indique si le code est inclus ou non dans SQLite pour lui permettre de fonctionner en toute sécurité dans un environnement multithread. La valeur par défaut est SQLITE_THREADSAFE=1
. Cela signifie mode sérialisé . Dans ce mode:
Dans ce mode (qui est la valeur par défaut lorsque SQLite est compilé avec SQLITE_THREADSAFE = 1), la bibliothèque SQLite sérialisera elle-même l'accès aux connexions de base de données et aux instructions préparées, de sorte que l'application puisse utiliser la même connexion à la base de données ou la même instruction préparée dans différents threads en même temps.
Utilisez la fonction sqlite3_threadsafe()
pour vérifier l’indicateur de compilation SQLITE_THREADSAFE
de la bibliothèque SQLite.
Le comportement de sécurité du thread de bibliothèque par défaut peut être modifié via sqlite3_config()
. Utilisez les indicateurs SQLITE_OPEN_NOMUTEX
et SQLITE_OPEN_FULLMUTEX
dans sqlite3_open_v2()
pour ajuster le mode de threading des connexions de base de données individuelles.
Résumé
Les transactions dans SQLite sont sérialisables.
Les modifications apportées dans une connexion de base de données sont invisibles pour toutes les autres connexions de base de données antérieures à la validation.
Une requête voit toutes les modifications effectuées sur la même connexion à la base de données avant le début de la requête, que ces modifications aient été validées ou non.
Si des modifications sont apportées à la même connexion à la base de données après le début de l'exécution d'une requête, mais avant la fin de la requête, il n'est pas défini si la requête verra ou non ces modifications.
Si des modifications sont apportées à la même connexion à la base de données après le début de l'exécution d'une requête, mais avant la fin de celle-ci, celle-ci peut renvoyer une ligne modifiée plusieurs fois ou peut-être une ligne précédemment supprimée.
Pour les besoins des quatre éléments précédents, deux connexions de base de données utilisant le même cache partagé et activant PRAGMA read_uncommitted
sont considérées comme étant la même connexion de base de données, et non des connexions de base de données séparées.
En plus des informations ci-dessus sur l'accès multi-thread, il pourrait être intéressant de jeter un œil à cette page sur l'isolation , car beaucoup de choses ont changé depuis cette question initiale et l'introduction du journal à écriture anticipée (WAL).
Il semble qu'une approche hybride consistant à ouvrir plusieurs connexions à la base de données offre des garanties de concurrence suffisantes, compensant les frais liés à l'ouverture d'une nouvelle connexion et offrant l'avantage de permettre des transactions d'écriture multithreads.