Forum: PC-Programmierung SQlite - rowid kommt mehrfach vor


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Joachim D. (Firma: JDCC) (scheppertreiber)


Bewertung
0 lesenswert
nicht lesenswert
Servus,

folgendes Problem:

Ich entwickle eine Archivsoftware unter SQLite + Web, das System ist
aktiv und läuft. Sporadisch (ca. 20 mal in den letzten 2 Jahren) tritt
ein merkwüdiges Problem auf: Ich habe mehrfach vergebene rowids, die
Daten nur des letzten Records sind in der db.

Programmausschnitt:

erstes db-Handle: offene Zieedatebank, attached ist eine weitere db
mit Daten. Die Dateen sollen von de zweiten in die erste transferiert
werden (es sind unterschiedliche db-files).

begin immediate
insert into archiv eetcpp.
return value == 0 -> alles ok, löschen in der ersten und end transaction
return value != 0 -> rollback; und Ende

Im Fehlerfall erscheint bei bis zu 5 aufeinandelfolgenden inserts die
gleiche rowid - darf ja eigentlich nicht seein. Alle returns von SQLite
sind 0 und versuchen mir zu sagen, alles sei ok.

Während der transaction aktualisiere ich noch eine andere Datenbank
über eine andere connection.

Gefunden habe ich das auf der Suche nach fehlenden Belegen. 
Protokolliert
ist der Vorgang auch (Ausschnitt):

----------------------

Barcode 60000000078034
  Ablagedatum (BELEG_DATUM = 15.05.2015) 15.05.2015, Ablagejahr 2015
  execute ARCHIV: 'attach 'E:\++++\AKTUELL\ruk\temp\archiv.sdb' as 
'tempdb''
    0.0000 sec, 1 Versuch(e)
    Standard-Barcode E:\++++\AKTUELL\ruk\temp\03379876.pdf
  Schreibe PDF        : E:\++++\AKTUELL\ruk\temp\03379876.pdf -> 
E:\ACCON\AKTUELL\ruk\2015\archiv_0515.t, 4960708 Bytes at $073afb4c
  execute ARCHIV: 'begin immediate'
    0.0000 sec, 1 Versuch(e)

  Aktualisiere History für '60000000078034', Jahr 2015
  execute HISTORY: 'update history set PRTFILE  = 
'usquery_impidx_20170303-08001014.prt, 
usquery_impwf_20170307-12001024.prt',
    LOCATION = 'ruk/2015', ARCDAT = '2017-03-07', STATUS = 'archiviert' 
where BARCODE_NR = '60000000078034''
    0.0000 sec, 1 Versuch(e)
  SQLAppend INSERT INTO ARCHIV
    (FPOS,BARCODE_NR,BELEG_DATUM,BELEG_KZ,BELEG_NR,BELEG_NUMMER,BEL_ART,BETR 
AG_1,BETRAG_2,BETRAG_3,BETRAG_4,BRUTTO,BUCHUNG_DATUM,KOMMENTAR,LOESCH_KZ 
,NETTO,REGULIERUNGS_KZ,SAP_BU_KREIS_R3,SAP_MA_NR_R3,SCANDATUM_R3,URSP_KZ 
,VL_NR,VORGANGS_ID,VORGANGS_NR,WAEHRUNG,WAWI_NR,REISENDER,WF_Import,SaKo 
nto,KOSTSTELL,SCANDATE,LOGFILE,IDXNR)
    VALUES
    ('0515 
73afb4c','60000000078034','2015-05-15','R','','69007827','00100032','000 
000000','000000000','000000000','000000000','226,86','2015-05-15','MS 
HAMBURG 
HAM1515','X','226,86','0','0008','60','','0000000000','2008','0000000000 
0000000000','00000000000000','EUR','00000','','03.03.2017','445030','',' 
','','03379876'),  result 0
  rowid 383721
  Lösche aus temp: delete from tempdb.archiv where BARCODE_NR = 
'60000000078034' = 0
  end transaction = 0
  detach temp = 0
  ok
  -> archiviert

---------------

Der Beleg ist dann weg. Der nächste hat die gleiche rowid ...

Vielleicht hat jemand eine Idee (im Web habe ich nur gefunden daß SQLite
das alles kann). Die Änderung in HISTORY sind vorhanden, die anderen 
nicht.

von Clemens L. (c_l)


Bewertung
1 lesenswert
nicht lesenswert
Joachim D. schrieb:
> Ich habe mehrfach vergebene rowids, die Daten nur des letzten Records
> sind in der db.

Das hört sich so an, als ob die vorherigen Daten nicht wirklich 
geschrieben wurden.

Benutzt du Netzwerk-Dateisystem oder virtuelle Maschinen (siehe 
http://www.sqlite.org/howtocorrupt.html)?

von Joachim D. (Firma: JDCC) (scheppertreiber)


Bewertung
0 lesenswert
nicht lesenswert
Hi Clemens,

läuft unter Apache auf Win7.

Die Daten werden nicht geschrieben, es ist immer nur der letzte
mit der rowid x in der db.

von Jörg M. (derlang)


Bewertung
0 lesenswert
nicht lesenswert
Gibt es ein Unique-Constraint auf dem Attribut?

Sorry, vergiss es, hab an etwas anderes gedacht....

: Bearbeitet durch User
von Joachim D. (Firma: JDCC) (scheppertreiber)


Bewertung
0 lesenswert
nicht lesenswert
Nein. Ist eigentlich alles ganz primitiv aufgebaut ;)

von Clemens L. (c_l)


Bewertung
0 lesenswert
nicht lesenswert
Das könnte ein Fehler in deinem Code sein ...

von Joachim D. (Firma: JDCC) (scheppertreiber)


Bewertung
0 lesenswert
nicht lesenswert
Clemens L. schrieb:
> Das könnte ein Fehler in deinem Code sein ...

Schön wär's ;)

Ich habe das einige Male pingelig kontrolliert, ich befürchte Nein.
Im Moment bin ich schlicht ratlos.

Es passiert ja auch ziemlich selten ...

Nach dem Datenimport (jeweils ein PDF und Indexdaten) läuft ein
Prüfprogramm was zu jeder rowid prüft ob die Sachen da sind. Das
hat dann natürlich keinen Fehler gefunden. Vor ein Paar Wochen
habe ich die Prüfung af rowid und Barcode_Nr erweitert und bin
so auf den Effekt gekommen.

von Bert3 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>ein merkwüdiges Problem auf: Ich habe mehrfach vergebene rowids

lass mich raten wie das Abläuft

1. gibts die rowid schon? -> nein -> Insert <- das ist der Fehler in 
deiner Erkennung
2. Update rowid-Satz auf neue Daten -> alter Satz wird auch 
überschrieben

https://www.techonthenet.com/sqlite/unique.php

sowas ohne Constraint zu machen ist wie Autofahren ohne Gurt - er ist da 
- es wird dadurch sicherer - vermeidet Unfälle - NUTZE DEN GURT

mit einem Unique Constraint kannst du die doppelte rowid gar nicht ohne 
das SQLite einen Fehler meldet mit Insert in deine Datenbank bekommen - 
dein händisches Prüfen ist definitiv falsch - es kann nicht anders 
passieren

von Joachim D. (Firma: JDCC) (scheppertreiber)


Bewertung
0 lesenswert
nicht lesenswert
Moin Bert,

die rowid wird von SQLite vergeben. Ich habe da keinen Einfluß drauf.
Nach dem insert hole ich mir die von SQLite per 
sqkite3_last_insert_rowid()
ab.

von Andreas (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Poste doch erst mal dein Datenbankschema (.schema), am besten als 
Anhang.

von Sheeva P. (sheevaplug)


Bewertung
0 lesenswert
nicht lesenswert
Joachim D. schrieb:
> Ich entwickle eine Archivsoftware unter SQLite + Web, das System ist
> aktiv und läuft.

SQLite ist nur dann thread-safe, wenn man es a) entsprechend übersetzt 
und b) den Multithreading- oder Serialized-Modus einschaltet. Warum 
benutzt Du nicht eine richtige Datenbank wie PostgreSQL?

von Clemens L. (c_l)


Bewertung
0 lesenswert
nicht lesenswert
Joachim D. schrieb:
> Clemens L. schrieb:
>> Das könnte ein Fehler in deinem Code sein ...
>
> Schön wär's ;)
>
> Ich habe das einige Male pingelig kontrolliert, ich befürchte Nein.

Und woher soll ich wissen, ob du die hypothetischen Fehler erkennen 
kannst? (Und wenn du dazu in der Lage wärst, warum fragst du dann hier?)

von Joachim D. (Firma: JDCC) (scheppertreiber)


Bewertung
0 lesenswert
nicht lesenswert
Clemens L. schrieb:
> warum fragst du dann hier?

Um eine Entscheidungshilfe zu suchen.

Ich weiß nicht ob ich da Mist gebaut habe oder es ein Problem von
SQLite ist. Eigentlich ist es bei SQL ja nicht üblich, eine Transaktion
mit "alles ok" zu beenden und dann eine Nase zu drehen ;)

von Bert3 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>die rowid wird von SQLite vergeben. Ich habe da keinen Einfluß drauf.
>Nach dem insert hole ich mir die von SQLite per
>sqkite3_last_insert_rowid() ab.

hast du mehrere Threads welche die selbe connection nutzen - oder kann 
dein "Web" das verursachen?

würde aber nur dazu führen können das du z.B. eine falsche rowid 
bekommst

und laut: https://www.sqlite.org/autoinc.html

>In SQLite, table rows normally have a 64-bit signed integer ROWID which is 
>unique among all rows in the same table. (WITHOUT ROWID tables are the 
>exception.)

sollte es gar nicht möglich sein das du doppelte rowids im Table hast

ausser hier: https://www.sqlite.org/c3ref/last_insert_rowid.html

>If a separate thread performs a new INSERT on the same database connection >while 
the sqlite3_last_insert_rowid() function is running and thus changes >the last 
insert rowid, then the value returned by >sqlite3_last_insert_rowid() is 
unpredictable and might not equal either >the >old or the new last insert rowid.

und darüber der text bezüglich "funktioniert" und nicht funktioniert ist 
auch ein wenig schwierig

imer Internt habe ich noch diesen Tip gefunden

>  begin;
>    insert into tbl( filed ) VALUES ( 1 );
>    Select last_insert_rowid() as li;
>  commit;

von Clemens L. (c_l)


Bewertung
0 lesenswert
nicht lesenswert
Joachim D. schrieb:
> Ich weiß nicht ob ich da Mist gebaut habe oder es ein Problem von
> SQLite ist.

Dass es ein Bug in SQLite ist, ist extrem unwahrscheinlich.

Dass du ein Dateisystem/OS/Hardware benutzt, das die Daten einfach 
wegschmeißt, hast du oben ausgeschlossen. Also bleiben nur Fehler im 
Zusammenhang mit Threading, oder irgendwelche anderen Programmierfehler.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Bewertung
0 lesenswert
nicht lesenswert
> Dass es ein Bug in SQLite ist, ist extrem unwahrscheinlich.

Äh ... klar. Ich glaube das ja auch nicht (und weiß es nicht).

> Dass du ein Dateisystem/OS/Hardware benutzt, das die Daten einfach
> wegschmeißt, hast du oben ausgeschlossen. Also bleiben nur Fehler im
> Zusammenhang mit Threading, oder irgendwelche anderen Programmierfehler.

Oder nicht so verwendet wie sich SQLite das gedacht hat. Das Problem
ist, ich kann es nicht bewußt herbeiführen - dazu passiert es zu selten.
Aktuell wurde knapp 400.000 Belege so bearbeitet, 2 mal hat es gezickt.

Ich könnte mir vorstellen, daß SQLite vielleicht ein Problem mit der
transaction und der in einer anderen connection geöffneten Datenbank
hat. Vielleicht bezieht sich die transaction nur genau auf die
aktuelle connnectioon (das Web sagt, es gehe).

Wenn ich da irgendwo Mist gebaut habe, kann ich das wenigstens abstellen 
;)

von Clemens L. (c_l)


Bewertung
0 lesenswert
nicht lesenswert
Joachim D. schrieb:
> Ich könnte mir vorstellen, daß SQLite vielleicht ein Problem mit der
> transaction und der in einer anderen connection geöffneten Datenbank
> hat. Vielleicht bezieht sich die transaction nur genau auf die
> aktuelle connnectioon (das Web sagt, es gehe).

Zwischen Connections und Transaktionen ist eine 1:1-Beziehung. Mit 
Transaktionen kannst du verschieden Connections voneinander isolieren.

Aber ich habe keine Ahnung, ob dein Code Transaktionen korrekt benutzt.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Bewertung
0 lesenswert
nicht lesenswert
Clemens L. schrieb:
> Zwischen Connections und Transaktionen ist eine 1:1-Beziehung. Mit
> Transaktionen kannst du verschieden Connections voneinander isolieren.

Bedeutet ?

Ich habe in einer trasnsaction 2 aktive connections. Das sollte
eigentlich ok sein und funktionieren ...

von Clemens L. (c_l)


Bewertung
0 lesenswert
nicht lesenswert
Eine Connection erhältst du mit sqlite3_open(). Ein ATTACH erzeugt keine 
neue Connection.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Bewertung
0 lesenswert
nicht lesenswert
Clemens L. schrieb:
> Eine Connection erhältst du mit sqlite3_open(). Ein ATTACH erzeugt keine
> neue Connection.

Klar.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.