SQLite - database is locked Unable to fetch row

Alles rund um die Programmierung mit Qt
Antworten
Tilman Räger
Beiträge: 189
Registriert: 6. Juni 2007 15:23
Wohnort: Göttingen

SQLite - database is locked Unable to fetch row

Beitrag von Tilman Räger »

Hallo,

ich habe eine Anwendung geschrieben, die Fehlermeldungen annimmt, in einer Datenbank speichert und weiterverarbeitet (emails / SMS versenden etc.) Zur Übersicht über die bisher aufgetretenen Fehler (und deren Verarbeitungsstand) zeige ich die Tabellen in 2 QSqlTableViews an. Als Datenbank verwende ich SQLite.

Nun bekomme ich des öfteren die oben genannte Fehlermeldung beim Speichern eines neuen Datensatzes (mittels SQL-Query "INSERT INTO ....". Nach dem was ich bisher im Netz gefunden habe, kommt der Fehler, wenn die QSqlTableViews gerade zu dem Zeitpunkt, an dem der neue Datensatz gespeichert werden soll, ihre Query zum Update durchführen.

Gibt es eine Möglichkeit, diese Konflikte zu vermeiden - oder zumindest sicherzustellen, das das Speichern Priorität hat? Oder ist die einzige Möglichkeit, zu Versuchen die Abfrage nur noch auf Anfrage zuzulassen und diese nur noch z.B. 1 mal pro Minute durchzuführen um Konflikte zu minimieren? Oder liegt das Problem möglicherweise ganz woanders?

Für alle Antworten schon mal im voraus Danke.

Gruss
Tilman (Räger)
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Re: SQLite - database is locked Unable to fetch row

Beitrag von RHBaum »

mit QSqlTableView meinst du die Kombi aus QSqlTableModell und QTableView richtig ?
Gibt es eine Möglichkeit, diese Konflikte zu vermeiden - oder zumindest sicherzustellen, das das Speichern Priorität hat?
Klar, die wirst nur nicht hören wollen :-)
DU hasst 2 völlig voneinander getrennte Model + Views, die allein nur ueber die connection der Datenbank Informationen austauschen.
Grad bei SQLite sind auch die Möglichkeiten da beschränkt, bei anderen RDBMS hasst du mehr optionen .... was eigentlich aber auch ned viel hilft.
Datenbanksysteme sind für Multiprozessing und Networking ausgelegt.
DU hasst aber alles in einem Prozess ! und das solltest du nutzen !

Vergiss die SQLTable ... scheiss.
Bau dir Datenklassen selber, die sich nur durch eine SQL Connection serialisieren ....
Lese und Schreibe nur so oft es notwendig ist ... aka nur wenn du wirklich multiuser auf der DB hasst musst du zeitnah updaten und lesen.
Bist du der einzige Nutzer ... kannst du lesen und schreiben wenns lustig bist, schlimmsten (besten)falls expliziet nur beim öffnen und "Speichern" ggf getriggert durch das Schliessen.

Deine Datenklasse sollte die Views informieren, wenn sich daten geändert haben und vor allen wo ...
Dann kannst zeitnah immer auf allen views die daten aktuell halten ohne zu pollen.
Das tut am Ende auch der Performance gut.
Durch die eigene Datenhaltung potentieren sich deine Möglichkeiten .....

Die fertigen SQL TableDInger sind wirklich nur für absolut generische unkomplizierte einfache Blicke auf ne DB gut. Sobald was Spezielleres, oder komplexeres kommt, kannst die Dinger ganz schnell verwerfen ...

Ciao ...
Tilman Räger
Beiträge: 189
Registriert: 6. Juni 2007 15:23
Wohnort: Göttingen

Re: SQLite - database is locked Unable to fetch row

Beitrag von Tilman Räger »

Hallo
RHBaum hat geschrieben:mit QSqlTableView meinst du die Kombi aus QSqlTableModell und QTableView richtig ?
Exakt. Ich hab das ganze gestern ohne Blick in den Quellcode geschrieben und hatte deswegen die korrekten Klassennamen nicht im Kopf und hab beides zusammengezogen. Aber es ist diese Kombination.
Gibt es eine Möglichkeit, diese Konflikte zu vermeiden - oder zumindest sicherzustellen, das das Speichern Priorität hat?
Klar, die wirst nur nicht hören wollen :-)
DU hasst 2 völlig voneinander getrennte Model + Views, die allein nur ueber die connection der Datenbank Informationen austauschen.
Grad bei SQLite sind auch die Möglichkeiten da beschränkt, bei anderen RDBMS hasst du mehr optionen .... was eigentlich aber auch ned viel hilft.
Datenbanksysteme sind für Multiprozessing und Networking ausgelegt.
DU hasst aber alles in einem Prozess ! und das solltest du nutzen !
Leider nicht ganz - die Annahme der Alarme und Speicherung derselben erfolgt über einen eigenen Thread, hatte ich vergessen zu erwähnen - sorry.

Vergiss die SQLTable ... scheiss.
Bau dir Datenklassen selber, die sich nur durch eine SQL Connection serialisieren ....
Lese und Schreibe nur so oft es notwendig ist ... aka nur wenn du wirklich multiuser auf der DB hasst musst du zeitnah updaten und lesen.
Bist du der einzige Nutzer ... kannst du lesen und schreiben wenns lustig bist, schlimmsten (besten)falls expliziet nur beim öffnen und "Speichern" ggf getriggert durch das Schliessen.
Die Anwendung ist der einzige Nutzer. Die Datenbank wird lediglich zum internen Speichern und Abfragen der eingegangenen Alarme benötigt, die Views selbst sind eigentlich auch nur zur Übersicht da (zusätzliches 'Schmankerl') und nicht wirklich erforderlich. Wenn's sein müsste, könnte ich auf die auch verzichten.
Deine Datenklasse sollte die Views informieren, wenn sich daten geändert haben und vor allen wo ...
Das tut sie momentan schon - möglicherweise ist das auch der Grund für den Fehler:
1.Alarm kommt - wird problemlos gespeichert
2. Signal an den TableView zwecks Update
3. Neuer Alarm kommt - bevor das Update beendet ist -> Fehler!

Momentan habe ich mal (aufgrund diverser Eintragungen im Internet) die Queries alle mit einem sauberen 'QSqlQuery::finish()' beendet, obwohl dies ja vermutlich durch den Destruktor eh vorgenommen wird (Die QSqlQuery-Objekte sind alle lokal in den einzelnen Funktionen definiert). Mal sehen, ob's hilft. Blöd ist nur, das dieser Fehler bisher nur beim Kunden - und da auch nur an 1. Tag, da allerdings massiv - aufgetreten ist. Einen Grund hierfür konnte ich bisher nicht finden - übermässig voll ist die Datenbank nicht (183 Datensätze).

Gruss
Tilman (Räger)
odt
Beiträge: 128
Registriert: 12. August 2010 11:49
Kontaktdaten:

Re: SQLite - database is locked Unable to fetch row

Beitrag von odt »

ich vermute, dass der SQL-Zugriff nicht mutlithread-safe ist. d.h. wenn gleichzeitig der Hintergrund-Thread speichert und das GUI zugreift "chlöpft's" sporadisch. Ob Du dies mit Locking hinkriegst, bezweifle ich (da das tief in der QSqlTable.. sein müsste).

Ich würde eher die Alarme vom Background-Thread in den GUI-Thread "emitten" und dort speichern.

Oder Du könntest probieren, zwei QSqlDatabase (d.h. je Thread) auf die SQLite zu öffnen. Evt. müsstest Du SQLite entsprechend konfigurieren/compilieren https://www.sqlite.org/threadsafe.html.
ODT Informatik GmbH, Reto Tschofenig
Tilman Räger
Beiträge: 189
Registriert: 6. Juni 2007 15:23
Wohnort: Göttingen

Re: SQLite - database is locked Unable to fetch row

Beitrag von Tilman Räger »

Hallo,
odt hat geschrieben:ich vermute, dass der SQL-Zugriff nicht mutlithread-safe ist. d.h. wenn gleichzeitig der Hintergrund-Thread speichert und das GUI zugreift "chlöpft's" sporadisch. Ob Du dies mit Locking hinkriegst, bezweifle ich (da das tief in der QSqlTable.. sein müsste).

Ich würde eher die Alarme vom Background-Thread in den GUI-Thread "emitten" und dort speichern.
Dann würde ich wohl eher die TableViews deaktivieren bzw. das dahinter liegende Model so ändern, das es die Daten vom anderen Thread periodisch abfragt.
Oder Du könntest probieren, zwei QSqlDatabase (d.h. je Thread) auf die SQLite zu öffnen. Evt. müsstest Du SQLite entsprechend konfigurieren/compilieren https://www.sqlite.org/threadsafe.html.
Das habe ich momentan schon. Bei der Konfiguration gehe ich eigentlich davon aus, das Qt das schon korrekt macht.

Gruss
Tilman (Räger)
odt
Beiträge: 128
Registriert: 12. August 2010 11:49
Kontaktdaten:

Re: SQLite - database is locked Unable to fetch row

Beitrag von odt »

Ob das Deaktivieren "genügt"? Aber die Alarme vom Hintergrund-Thread zur "Anzeige" emitten wäre auch ne Lösungsvariante.

PS: Bist Du sicher, dass Du wirklich zwei QSqlDatabase's hast? Ich hatte mal ein Problem, dass ich zwar zwei hatte, Qt intern aber aufgrund des Names nur eine effekte Connection aufbaute. Eine Connection sollte nicht von mehreren Threads verwendet werden, zumindest verstehe ich das so:
Multi-thread. In this mode, SQLite can be safely used by multiple threads provided that no single database connection is used simultaneously in two or more threads.
ODT Informatik GmbH, Reto Tschofenig
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Re: SQLite - database is locked Unable to fetch row

Beitrag von RHBaum »

Leider nicht ganz - die Annahme der Alarme und Speicherung derselben erfolgt über einen eigenen Thread
Thread != Prozess

Aber zum Thema ...
SQLITE ist "threadsafe", leider bedeutet das nicht, das man von mehreren Threads aus darauf rumnuckeln kann ^^

Deswegen würd ich zuerst sicherstellen, das nur ein thread, egal welcher das ist, lesen und schreiben kann auf der DB
Da die QSQL ...models alles in den GUI thread mappen, sind die für sowas eh nicht wirklich verwendbar

Also um nen eigenes Model mit Datenklasse und threadmanagement kommst da nicht drumherum ....

Ciao ...
Antworten