Datenbankensperren

Alle Fragen um die Programmierung, die sich sonst nicht kategorisieren lassen. Von Makro bis Codeblock, von IF bis ENDIF

Moderator: Moderatoren

Antworten
Benutzeravatar
andreas
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1902
Registriert: Mi, 28. Sep 2005 10:53
Wohnort: Osnabrück
Hat sich bedankt: 4 Mal
Kontaktdaten:

Datenbankensperren

Beitrag von andreas »

Hallo Leute,

ich habe bei einem Kunden ein Problem, vermuttlich bei der Dateisperre.
In einer Datei mit einem Datensatz wird die Nummern gespeichert, die für die forlaufende Nummerierung benutzt werden. Es gibt nur eine Funktion, die Zugriff auf diese Datei hat und die Nummern zurückgibt. Diese Funktion läuft in einer Endlosschleife so lange, bis die Datei exclusive geöffnet werden konnte.

Das Problemm ist, dass immer wieder doppelte Nummern vergeben werden.

Das Programm läuft im Netzwerk. Die Daten liegen auf einem Windows 2003 Server und werden über ein verbundenes Laufwerk benuzt.
Die Clients sind Windows 98 PCs wegen Produktionshalle und viel Dreck auf kleinen PCs mit CF-Karten anstatt Festplatten.
Gruß,

Andreas
VIP der XUG Osnabrück
thomas
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 116
Registriert: Fr, 23. Sep 2005 16:07
Wohnort: Bad Oldesloe
Kontaktdaten:

Beitrag von thomas »

Hallo Andreas.

Ich habe eine ganz ähnliche Funktion im Einsatz, jedoch wird die Datenbank ganz normal geöffnet und
die laufende Nummer wird dann bei erfolgreicher Datensatzsperre (RLOCK()) erhöht. Insgesamt sind ca.
32 User im Parallelbetrieb und bisher wurde noch keine doppelte Nummer vergeben (Toi Toi Toi).
Aber vielleicht kannst Du uns Deine Funktion posten ?
Benutzeravatar
andreas
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1902
Registriert: Mi, 28. Sep 2005 10:53
Wohnort: Osnabrück
Hat sich bedankt: 4 Mal
Kontaktdaten:

Beitrag von andreas »

Hallo Thomas,

ich habe das früher auch mit nur den Datensatz gesperrt gehabt, hat aber auch zum gleichen Problem geführt. Deswegen habe ich auf die Dateisperre umgestellt, was das Problem eigentlich beseitigen sollte. Gestern kamm aber wieder eine doppelnummer hintereinander.
Unten findest du die Funktionen. Ich lasse die auskommentierten Zeilen von der Datensatzsperre drin, damit du das sehen kannst, wie es vorher war.

Code: Alles auswählen

FUNCTION GetNummer(cAuswahl)
	local nAuftragNeu:=0, cAuftragNeu:="", db:=select(), nJahr:=YEAR(date())
	/*
	Local aStruckt:={;
		{"Jahr","N",2,0},;
		{"Auftrag","N",7,0},;
		{"LaufKarte","N",7,0},;
		{"Behaelter","N",9,0},;
		{"Liefersch","N",8,0};
		}
	 */

	Default cAuswahl to "AUFTRAG"

	/*
	IF ! file("Nummern.dbf")
		dbcreate("Nummern", aStruckt, "FOXCDX")
	ENDIF
	*/
	IF len(alltrim(str(nJahr)))==4

		nJahr:= val(substr(alltrim(str(nJahr)),3))
	ENDIF



	*use Nummern alias Nummern via "FOXCDX" new exclusive

	do while ! DBNummerOpen()
	enddo

	*IF ! neterr()

	IF lastrec()==0
		dbappend()
		replace nummern->jahr with nJahr
		*dbrunlock()

	ENDIF

	go 1
	*do while ! dbrlock()
	*enddo

	IF nJahr > nummern->jahr
		**zurücksetzen der Werte, wenn das Jahr sich gewechselt hat
		replace nummern->jahr with nJahr
		replace nummern->auftrag with 0
		replace nummern->LaufKarte with 0
		replace nummern->Behaelter with 0
		replace nummern->Liefersch with 0
	ENDIF


	IF upper(cAuswahl)=="AUFTRAG"

		nAuftragNeu:=nummern->auftrag+1
		replace nummern->auftrag with nAuftragNeu
		cAuftragNeu:="A"+strzero(nJahr,2)+strzero(nAuftragNeu,7)

	elseIF upper(cAuswahl)=="LAUFKARTE"

		nAuftragNeu:=nummern->LaufKarte+1
		replace nummern->LaufKarte with nAuftragNeu
		cAuftragNeu:="LK"+strzero(nJahr,2)+strzero(nAuftragNeu,7)

	elseIF upper(cAuswahl)=="BEHAELTER"

		nAuftragNeu:=nummern->Behaelter+1
		replace nummern->Behaelter with nAuftragNeu
		cAuftragNeu:="B"+strzero(nJahr,2)+strzero(nAuftragNeu,9)

	elseIF upper(cAuswahl)=="LIEFERSCHEIN"

		nAuftragNeu:=nummern->Liefersch+1
		replace nummern->Liefersch with nAuftragNeu
		cAuftragNeu:="HL"+strzero(nJahr,2)+strzero(nAuftragNeu,8)

	ENDIF
	*dbrunlock()

	close Nummern


	*ENDIF

	IF db>0
		select (db)
	ENDIF

RETURN cAuftragNeu


FUNCTION DBNummerOpen
	local lOk := .f.
	Local aStruckt:={;
		{"Jahr","N",2,0},;
		{"Auftrag","N",7,0},;
		{"LaufKarte","N",7,0},;
		{"Behaelter","N",9,0},;
		{"Liefersch","N",8,0};
		}

	IF ! file("Nummern.dbf")
		dbcreate("Nummern", aStruckt, "FOXCDX")
	ENDIF

	bSaveError := ErrorBlock()
	ErrorBlock( {|e| Break(e)} )

	BEGIN SEQUENCE

		use Nummern alias Nummern via "FOXCDX" new exclusive
		IF ! neterr()
			lOk := .t.
		else
			lOk := .f.
		endif

	RECOVER
		ErrorBlock( bSaveError )
		lOk := .f.
	END SEQUENCE
	ErrorBlock( bSaveError )

RETURN lOk
Gruß,

Andreas
VIP der XUG Osnabrück
thomas
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 116
Registriert: Fr, 23. Sep 2005 16:07
Wohnort: Bad Oldesloe
Kontaktdaten:

Beitrag von thomas »

Hallo Andreas.

Deine Funktion sieht soweit Okay aus. Im Vergleich mit meiner Funktion vermisse ich bei Dir den DBCommit() vor der Zeile „close Nummern“. Vielleicht hilft das, zumindest hat meine Funktion per Heute schon 3.5 Mill. Unique Nummer vergeben.
Ein Tip : Ich benutze niemals „REPLACE“ ! (nummern->auftragnr := nummern->auftagnr+1)
Gruß

Thomas
Benutzeravatar
andreas
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1902
Registriert: Mi, 28. Sep 2005 10:53
Wohnort: Osnabrück
Hat sich bedankt: 4 Mal
Kontaktdaten:

Beitrag von andreas »

Hallo Thomas,

werden die Daten nicht automatisch gespeichert, wenn der Datensatz entsperrt oder die Datei geschlossen wird?
Wieso benutzt du niemals replace? Ist der Befehl so schlim.
Gruß,

Andreas
VIP der XUG Osnabrück
thomas
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 116
Registriert: Fr, 23. Sep 2005 16:07
Wohnort: Bad Oldesloe
Kontaktdaten:

Beitrag von thomas »

Hallo Andreas.

Ich kann Dir leider die Frage nicht 100%tig beantworten, ob nach dem Schließen der Datenbank alle geänderten Daten auch drinstehen oder noch irgendwo im Cache sind. In Deinem Fall kann DbCommit() nicht schaden. Wie oft kommen eigentlich solche doppelten Nummer vor ?
Die Benutzung von Replace ist einfach eine Geschmacksache.

Gruß

Thomas
Benutzeravatar
andreas
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1902
Registriert: Mi, 28. Sep 2005 10:53
Wohnort: Osnabrück
Hat sich bedankt: 4 Mal
Kontaktdaten:

Beitrag von andreas »

Ich glaube, dass es an gewonheit von Windows liegt, die Dateinamen in der Verknüpfung zu ändern, wenn die Datei nicht mehr da ist, wo die z.B. in diesen Moment umbenant wird. Der Kunde hatte nocht eine alte umbenannte Datei im Verzeichnis liegen, wo noch alte Methode mit Dbrlock() verwendet wurde. Es kann sein dass mindestens 2 PCs damit gearbeitet haben und das Problem verursacht haben. Da wäre das mit DBCommit() angesagt gewesen.
Ich habe erstmal die alte Datei gelöscht und werde erst abwarten, ob das Problem noch mal vorkommt.
Gruß,

Andreas
VIP der XUG Osnabrück
Antworten