10
votes

Le fichier de base de données est inexplicablement verrouillé lors de la validation de la SQLite

J'effectue un grand nombre d'insertions dans une base de données SQLITE. J'utilise un seul fil. Je lotte les écritures pour améliorer les performances et avoir un peu de sécurité en cas de crash. Fondamentalement, je me cache un tas de données en mémoire, puis lorsque je le souhaite approprié, je boucle sur toutes ces données et effectuez les inserts. Le code pour cela est indiqué ci-dessous:

    public DataBase(String path)
    {
        //build connection string
        SQLiteConnectionStringBuilder connString = new SQLiteConnectionStringBuilder();
        connString.DataSource = path;
        connString.Version = 3;
        connString.DefaultTimeout = 5;
        connString.JournalMode = SQLiteJournalModeEnum.Persist;
        connString.UseUTF16Encoding = true;

        using (connection = new SQLiteConnection(connString.ToString()))
        {
            //check for existence of db
            FileInfo f = new FileInfo(path);

            if (!f.Exists)  //build new blank db
            {
                SQLiteConnection.CreateFile(path);
                connection.Open();

                using (SQLiteTransaction trans = connection.BeginTransaction())
                {
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        command.CommandText = DataBase.CREATE_MATCHES;
                        command.ExecuteNonQuery();

                        command.CommandText = DataBase.CREATE_STRING_DATA;
                        command.ExecuteNonQuery();
                        //TODO add logging
                    }
                    trans.Commit();
                }
                connection.Close();
            }
        }            
    }


1 commentaires

Bien que vous ne souhaitiez pas avoir de petits commits - le problème se produit-il toujours lorsque vous déménagez sur Tran et de valider les trans dans la boucle de lot interne?


10 Réponses :


2
votes

est votre fichier de base de données sur la même machine que l'application ou est-ce qu'il est stocké sur un serveur?

Vous devez créer une nouvelle connexion dans chaque thread. Je serais simplifié la création d'une connexion, utilisez partout: connexion = nouvelle sqliteconnection (Connstring.tostring ());

et utilisez un fichier de base de données sur la même machine que l'application et testez à nouveau.

Pourquoi les deux façons différentes de créer une connexion?


0 commentaires

3
votes

choses à surveiller:

  • N'utilisez pas de connexions sur plusieurs threads / processus.

  • Je l'ai vu arriver lorsqu'un scanner de virus détecterait les modifications apportées au fichier et tenterait de le numériser. Il verrouille le fichier pour un intervalle court et causerait des ravages.


0 commentaires

2
votes

Ces gars ont eu des problèmes similaires (surtout, il apparaît, le fichier de journalisation étant verrouillé, peut-être des interactions tortoisisesvn ... Vérifiez les articles référencés).

Ils ont trouvé un ensemble de recommandations (répertoires corrects, changeant les types de journalisation de Supprimer vers Persist, etc.). http://sqlite.phxsoftware.com/forums/p/689/ 5445.aspx # 5445


Les options du mode journal sont discutées ici: http://www.sqlite.org/pragma.html . Vous pouvez essayer tronquer.

Y a-t-il une trace de pile à l'exception de SQL Lite?

Vous vous indiquez "lot mon engagement à un intervalle raisonnable". Quel est l'intervalle?


4 commentaires

L'utilisation de persist a peut-être réduit la fréquence de ce problème, bien que cela ne l'a pas éliminé. aussi userappdata était un bon appel. Merci!


Alors, d'où ça te quitte? Bien que je sois sûr que ce n'est pas censé être un problème est qu'il est possible que vous fassiez comme trop près (TIDise) ensemble?


whoops, je n'ai pas vu vos commentaires ci-dessus. Avez-vous essayé cela sur une autre machine? Y a-t-il une exception intérieure?


Avez-vous essayé tronqué? Avez-vous une trace de pile lorsque l'exception est lancée?



5
votes

exécuter moniteur de processus Sysinternals et filtrer sur le nom de fichier lors de l'exécution de votre programme Pour exclure si un autre processus lui fait quelque chose et de voir ce que votre programme est exactionnellement effectué dans le fichier. Long coup, mais pourrait donner un indice.


1 commentaires

Alors ... le problème était-il juste un autre processus enfermer le fichier?



2
votes

J'utiliserais toujours une connexion, une transaction et une commande dans un en utilisant la clause . Dans votre premier code, vous avez fait, mais votre troisième (création des tables) que vous n'avez pas. Je vous suggère de faire cela aussi, car (qui sait?) Peut-être que les commandes qui créent la table continuent de verrouiller le fichier. Long Shot ... mais vaut un coup?


1 commentaires

Malheureusement, cela n'a pas fait l'affaire, mais c'est probablement la meilleure façon de le faire de toute façon, j'ai mis à jour mon code en conséquence ... THX!



2
votes

Avez-vous une recherche Google Desktop (ou un autre index de fichier) en cours d'exécution? Comme mentionné précédemment, SYSInternals Process Monitor peut vous aider à le suivre.

Aussi, quel est le nom de fichier de la base de données? De PerformanceCeTuningWindows :

Être très, très attentif à quoi vous nommez votre base de données, en particulier l'extension

Par exemple, si vous donnez toutes vos bases de données l'extension .sdb (base de données SQLite, Nice Nom Hey? Je l'ai pensé quand je le choisissais de toute façon ...) Vous découvrez que l'extension SDB est déjà associée à des packages Appfix. < / p>

Maintenant, voici la partie mignonne, Appfix est un exécutable / emballage que Windows XP reconnaît, et que la mine) ajoutez la base de données à la fonctionnalité de restauration du système

Cela signifie, restez avec moi ici, chaque fois que vous écrivez quelque chose à la base de données, le système Windows XP pense qu'une exécutable sanglante a changé et copie toute votre base de données de 800 MEG au répertoire de restauration du système ....

Je recommande quelque chose comme dB ou dat.


0 commentaires

11
votes

On dirait que vous n'aviez pas réussi à lier la commande avec la transaction que vous avez créée. Au lieu de: xxx

Vous devez utiliser: xxx

ou vous pouvez définir sa propriété de transaction après sa construction.

Pendant que nous en sommes - votre manipulation des défaillances est incorrecte:

La méthode exécutenonquery de la commande peut également échouer et vous n'êtes pas vraiment protégé. Vous devriez changer le code à quelque chose comme: xxx

Une autre chose est que vous n'avez pas besoin de mettre en cache quelque chose en mémoire. Vous pouvez compter sur le mécanisme de journalisation SQLite pour stocker l'état de transaction incomplète.


2 commentaires

En outre, je suis content que vous mentionniez la mise en cache. À l'origine, je le faisais comme vous le suggérez, mais je me suis éloigné de cela depuis que je craignais que cela contribuait à ce désordre d'échec de validation. Une fois que je le travaille, je vais retourner et poster des échantillons de code appropriés ...


Eh bien, j'ai essayé les deux méthodes - construire en passant dans la transaction et en définissant la propriété post-hoc. ni n'a permis de soulager mon problème. Merci pour les suggestions!



5
votes

Nous avons eu un problème très similaire utilisant des transactions imbriquées avec la classe de transactionsCope. Nous pensé toutes les actions de la base de données se sont produits sur le même thread ... Cependant, nous avons été pris par le mécanisme de transaction ... plus spécifiquement la transaction ambiante.

Il y avait une transaction plus haut en haut de la chaîne Lequel, par la magie de l'ADO, la connexion s'est automatiquement enrôlée. Le résultat était que, même si nous pensions que nous écrivions à la base de données sur un seul fil, l'écriture n'a pas réellement eu lieu tant que la transaction la plus haute n'a pas été commise. À ce point "indéterminé", la base de données a été écrite à l'amener à être verrouillée à l'extérieur de notre contrôle.

La solution consistait à garantir que la base de données SQLite ne participe pas directement à la transaction ambiante en garantissant que nous avons utilisé quelque chose comme: xxx


0 commentaires

3
votes

J'ai commencé à faire face à ce même problème aujourd'hui: j'étudie ASP.NET MVC, construisant ma première application complètement à partir de zéro. Parfois, lorsque j'écrirais dans la base de données, j'avais la même exception, affirmant que le fichier de base de données était verrouillé.

Je l'ai trouvé vraiment étrange, car j'étais complètement sûr qu'il n'y avait qu'une seule connexion ouverte à cette époque (sur la base de la liste des poignées actives de Process Explorer).

J'ai également construit l'ensemble de la couche d'accès aux données à partir de zéro, à l'aide du fournisseur System.Data.SQLite .NET .NET et, lorsque je l'ai prévu, j'ai pris des soins particuliers avec des connexions et des transactions, afin de vous assurer aucune connexion ou transaction. était laissé suspendu.

La partie délicate était que la définition d'un point d'arrêt sur la commande exécutenonconquery () et l'exécution de l'application en mode de débogage rendrait l'erreur disparaître! Googling, j'ai trouvé quelque chose d'intéressant sur ce site: http://www.softperfect.com /board/read.php?8 5775 . Là-bas, quelqu'un a répondu au fil suggérant l'auteur de mettre le chemin de la base de données sur la liste des ignorés anti-virus.

J'ai ajouté le fichier de base de données à la liste Ignore de mon anti-virus (Microsoft Security Essentials) et il a résolu mon problème. Plus d'erreurs de base de données verrouillées!


0 commentaires

0
votes

Bien que le verrou soit signalé sur le COMTT, le verrou est sur la commande insertion / mise à jour. Vérifiez que les serrures d'enregistrement ne sont pas publiés plus tôt dans votre code.


0 commentaires