Entwickler-Ecke
Datenbanken - BDE: Zu viele offene Tabellen vorhanden
jjturbo - Fr 09.07.10 09:33
Titel: BDE: Zu viele offene Tabellen vorhanden
Moin Forum,
ich habe in einem Projekt einen Fehler, den ich vor ein paar Jahren schon einmal in einem anderen Projekt hatte.
Die Funktion die mir den Ärger bereitet (Siehe unten) wird oft aufgerufen, etwa 300 mal pro Stunde.
Ichn habe mir eine Testumgebung geschaffen, in der ich den Fehler in etwa 10 Minuten reproduzieren kann.
Die Fehlermeldung lautet: "Zu viele offene Tabellen vorhanden".
Sie tritt immer auf in einer der Zeilen "MyQuery.Active := True;", ich prüfe noch, ob es evtl. immer in der gleichen Zeile auftritt.
Im Moment wird MyQuery zur Laufzeit erstellt und auch wieder freigegeben. Ich hatte vorher ein Query und eine DataSource verwendet, die auf Form1 verfügbar waren, aber auch mit diesem Fehler.
Hat jemand eine Idee?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227:
| procedure FA_ZurueckmeldenAnSAP(FA_Rueck:String); var Funct2 :Variant; TableOfConditions :Variant; TableCondRow :Variant; s :String; SQLText :String; Anz :Integer; Erg :Integer; ZeitStempel :String; CounterWert :Integer; DatenAnSapProt :Array of String; Nr :Integer; MyQuery :TQuery; MyDataSource :TDataSource; begin
if FA_Rueck = '' then Exit;
Funct2 := 0; TableOfConditions := 0; TableCondRow := 0;
if not sapConnected then begin Showmessage('Nicht mit SAP verbunden. Abbruch.'); Exit; end;
protokoll(clGreen,'Fertigungsauftrag zurückmelden: ' + FA_Rueck);
MyDataSource := TDataSource.Create(nil);
MyQuery := TQuery.Create(nil); with MyQuery do begin DataSource := MyDataSource; DatabaseName := Dir; end;
s := FA_Rueck; while Length(s) < 12 do s := '0' + s;
Funct2 := Form1.mySAPFunctions.add('Z_RFC_RUECKMELDUNG_SAEGE'); Funct2.exports('Auftrag').value := s;
TableOfConditions := Funct2.tables.item('DATATAB'); TableOfConditions.rows.removeAll;
MyQuery.Active := false; SQLText := 'select * from ' + RueckPufferTabelle + ' WHERE FA=' + FA_Rueck + ' AND NOT status="' + Text_Uebertragung_OK + '" AND Counter_Max_10 < 10'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL; MyQuery.Active := True; Anz := MyQuery.RecordCount;
if Anz = 0 then begin Protokoll(clBlue,'Keine zurückzumeldenden Teile in diesem FA'); MyQuery.Active := false; MyQuery.Free; MyDataSource.Free; Exit; end;
if not NurEinenDatensatzZurueckmelden then begin SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET rueckmeldenaktiv = 1 WHERE FA = ' + FA_Rueck + ' AND NOT status="' + Text_Uebertragung_OK + '" AND Counter_Max_10 < 10'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL; end; if NurEinenDatensatzZurueckmelden then Anz := 1; NurEinenDatensatzZurueckmelden := false;
SetLength(DatenAnSapProt,Anz+4); DatenAnSapProt[0] := 'SAPFunctions.add(Z_RFC_RUECKMELDUNG_SAEGE)'; DatenAnSapProt[1] := 'FA: ' + FA_Rueck; Nr := 2;
SQLText := 'select * from ' + RueckPufferTabelle + ' WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL; MyQuery.Active := True; MyQuery.First; while not MyQuery.Eof do begin TableCondRow := TableOfConditions.rows.add; TableCondRow.Value[1]:= MyQuery.FieldByName('Nacharbeit_J_N').AsString; TableCondRow.Value[2]:= MyQuery.FieldByName('Materialnummer').AsString; TableCondRow.Value[3]:= MyQuery.FieldByName('Aus Lagerort 0100/0200').AsString; TableCondRow.Value[4]:= MyQuery.FieldByName('Länge').AsString; MyQuery.Next; DatenAnSapProt[Nr] := 'DataTab Zeile' + IntToStr(Nr-1) + ': ' + TableCondRow.Value[1] + ';' + TableCondRow.Value[2] + ';' + TableCondRow.Value[3] + ';' + TableCondRow.Value[4]; inc(Nr); end;
Erg := 9999; TRY Erg := Funct2.call; EXCEPT protokoll(clRed,'Fehler in Funct2.call!'); Showmessage('Fehler in Funct2.call!'); END;
DatenAnSapProt[Nr] := 'Ergebnis Funktionsaufruf (32Bit Integer): ' + IntToStr(Erg); inc(Nr); DatenAnSapProt[Nr] := 'Exception-Text des RFC-Bausteins: ' + Funct2.Exception;
if Funct2.Exception = Text_Uebertragung_OK then begin
MyQuery.Active := false;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET status = "' + Funct2.Exception + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
ZeitStempel := DateToStr(Now) + ', ' + TimeToStr(Now); SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET zeitpunkt = "' + ZeitStempel + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
Protokoll(clGreen,'Übertragung erfolgreich! Anzahl: ' + IntToStr(Anz)); protokoll(clGreen,'Meldung des RFC-Bausteins: ' + Funct2.Exception); end else begin SQLText := 'SELECT * FROM ' + RueckPufferTabelle + ' WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
MyQuery.Active := True; CounterWert := StrToIntDef(MyQuery.FieldByName('Counter_Max_10').AsString,0)+1; MyQuery.Active := false;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET Counter_Max_10 = "' + IntToStr(CounterWert) + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET status = "' + Funct2.Exception + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
protokoll(clRed,'Übertragung nicht erfolgreich! Meldung des RFC-Bausteins: ' + Funct2.Exception); Application.BringToFront; end;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET rueckmeldenaktiv = 0 WHERE fa > 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
MyQuery.Active := false; MyQuery.Free; MyDataSource.Free;
end; |
mkinzler - Fr 09.07.10 09:37
Ich würde mir an deiner Stelle überlegen, ob ich weiter mit der BDE arbeiten würde. Du scheinst ja sowieso über ODBC o.ä. auf SAP zuzugreifen.
Das wären dann 2 bremsende Krücken.
jjturbo - Fr 09.07.10 09:46
Könnte ich auf meine Paradox-Tabellen z.B. auch einfach mit Zeos zugreifen?
mkinzler - Fr 09.07.10 09:53
Ach das sind Paradox-Tabellen. Dann würde ich Paradox auch gegen ein zeitgemässes DBMS ersetzen.
Für Paradox und dBase ist die BDE mehr als eine Zugriffskomponente, deshalb geht Zeos nicht
jjturbo - Fr 09.07.10 09:56
Was kannst Du denn als Ersatz empfehlen? Ich hättet gerne nach wie vor lokale Tabellen ohne einen Datenbankserver.
mkinzler - Fr 09.07.10 10:01
Ich persönlich würde dir dann zu FireBird (embedded) raten. Zum Entwickeln mit Server und später dann die embedded (Server)Client Lösung.
jjturbo - Fr 09.07.10 10:05
Bei den neueren Projekten nehmen wir Firebird mit Zeos.
ich denke mal drüber nach.
Aber zurück zu meinem Problem: Wenn die Funktion das 126. Mal aufgerufen wirds, dann passierts.
mkinzler - Fr 09.07.10 10:10
Du scheinst den Query nur im Fehlerfall zu schliessen ( oder ich habe es übersehen)
jjturbo - Fr 09.07.10 10:14
Du meinst mit MyQuery.Active := false?
Habe ich es irgendwo vergessen? Wenn, dann sehe ich die Stelle nicht.
---
Moderiert von
Narses: Beiträge zusammengefasst---
Korrektur: Immer im 125. Aufruf, immer an der zweiten Stelle mit MyQuery.Active := True;
mkinzler - Fr 09.07.10 10:25
In Zeile 98 verwendest du das bestehende Queryobjekt ohne das offene DataSet zu schliessen
In Zeile 198 ist ExecuteSQL falsch ( da Abfrage nicht DML)
Statt .Active auf True/False zu setzen würde ich .Open / .Close verwenden
jjturbo - Fr 09.07.10 10:36
Zu Zeile 98: Muß ich vor jedem ExecSQL MyQuery.Active := false setzen?
Worin unterscheiden sich denn .Active True/false und .Open/.Close
mkinzler - Fr 09.07.10 10:43
Jein. Es kommt adrauf an, was vorher gemacht wurde. Nach .ExecSQL ist es imho nicht notwendig, aber nach einer Abfrage, welche ja eine Datenmenge zurückliefert ( auch eine leere Datenmenge ist eine).
.Active := True ruft .Open bzw. .ExecuteSQL auf auf, ich bevorzuge es aber selbst zu machen
jjturbo - Fr 09.07.10 11:03
Habe es mal etwas abgeändert, so läuft es auf jeden schon mal länger, steht jetzt bei etwa 200 Funktionsaufrufen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220:
| procedure FA_ZurueckmeldenAnSAP(FA_Rueck:String); var Funct2 :Variant; TableOfConditions :Variant; TableCondRow :Variant; s :String; SQLText :String; Anz :Integer; Erg :Integer; ZeitStempel :String; CounterWert :Integer; DatenAnSapProt :Array of String; Nr :Integer; MyQuery :TQuery; MyDataSource :TDataSource; begin
inc(Nummer); form1.caption := IntToStr(nummer); if FA_Rueck = '' then Exit;
Funct2 := 0; TableOfConditions := 0; TableCondRow := 0;
if not sapConnected then begin Showmessage('Nicht mit SAP verbunden. Abbruch.'); Exit; end;
protokoll(clGreen,'Fertigungsauftrag zurückmelden: ' + FA_Rueck);
MyDataSource := TDataSource.Create(nil);
MyQuery := TQuery.Create(nil); with MyQuery do begin DataSource := MyDataSource; DatabaseName := Dir; end;
s := FA_Rueck; while Length(s) < 12 do s := '0' + s;
Funct2 := Form1.mySAPFunctions.add('Z_RFC_RUECKMELDUNG_SAEGE'); Funct2.exports('Auftrag').value := s;
TableOfConditions := Funct2.tables.item('DATATAB'); TableOfConditions.rows.removeAll;
MyQuery.Active := false; SQLText := 'select * from ' + RueckPufferTabelle + ' WHERE FA=' + FA_Rueck + ' AND NOT status="' + Text_Uebertragung_OK + '" AND Counter_Max_10 < 10'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.Active := True; Anz := MyQuery.RecordCount;
if Anz = 0 then begin Protokoll(clBlue,'Keine zurückzumeldenden Teile in diesem FA'); MyQuery.Active := false; MyQuery.Free; MyDataSource.Free; Exit; end;
if not NurEinenDatensatzZurueckmelden then begin SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET rueckmeldenaktiv = 1 WHERE FA = ' + FA_Rueck + ' AND NOT status="' + Text_Uebertragung_OK + '" AND Counter_Max_10 < 10'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL; end; if NurEinenDatensatzZurueckmelden then Anz := 1; NurEinenDatensatzZurueckmelden := false;
SetLength(DatenAnSapProt,Anz+4); DatenAnSapProt[0] := 'SAPFunctions.add(Z_RFC_RUECKMELDUNG_SAEGE)'; DatenAnSapProt[1] := 'FA: ' + FA_Rueck; Nr := 2;
MyQuery.Active := false; SQLText := 'select * from ' + RueckPufferTabelle + ' WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.Active := True; MyQuery.First; while not MyQuery.Eof do begin TableCondRow := TableOfConditions.rows.add; TableCondRow.Value[1]:= MyQuery.FieldByName('Nacharbeit_J_N').AsString; TableCondRow.Value[2]:= MyQuery.FieldByName('Materialnummer').AsString; TableCondRow.Value[3]:= MyQuery.FieldByName('Aus Lagerort 0100/0200').AsString; TableCondRow.Value[4]:= MyQuery.FieldByName('Länge').AsString; MyQuery.Next; DatenAnSapProt[Nr] := 'DataTab Zeile' + IntToStr(Nr-1) + ': ' + TableCondRow.Value[1] + ';' + TableCondRow.Value[2] + ';' + TableCondRow.Value[3] + ';' + TableCondRow.Value[4]; inc(Nr); end; MyQuery.Active := false;
Erg := 9999; TRY Erg := Funct2.call; EXCEPT protokoll(clRed,'Fehler in Funct2.call!'); Showmessage('Fehler in Funct2.call!'); END;
DatenAnSapProt[Nr] := 'Ergebnis Funktionsaufruf (32Bit Integer): ' + IntToStr(Erg); inc(Nr); DatenAnSapProt[Nr] := 'Exception-Text des RFC-Bausteins: ' + Funct2.Exception;
if Funct2.Exception = Text_Uebertragung_OK then begin
MyQuery.Active := false;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET status = "' + Funct2.Exception + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
ZeitStempel := DateToStr(Now) + ', ' + TimeToStr(Now); SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET zeitpunkt = "' + ZeitStempel + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
Protokoll(clGreen,'Übertragung erfolgreich! Anzahl: ' + IntToStr(Anz)); protokoll(clGreen,'Meldung des RFC-Bausteins: ' + Funct2.Exception); end else begin SQLText := 'SELECT * FROM ' + RueckPufferTabelle + ' WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.Active := True;
CounterWert := StrToIntDef(MyQuery.FieldByName('Counter_Max_10').AsString,0)+1; MyQuery.Active := false;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET Counter_Max_10 = "' + IntToStr(CounterWert) + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET status = "' + Funct2.Exception + '" WHERE rueckmeldenaktiv = 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
protokoll(clRed,'Übertragung nicht erfolgreich! Meldung des RFC-Bausteins: ' + Funct2.Exception); Application.BringToFront; end;
SQLText := 'UPDATE ' + RueckPufferTabelle + ' SET rueckmeldenaktiv = 0 WHERE fa > 1'; MyQuery.SQL.SetText(PChar(SQLText)); MyQuery.ExecSQL;
MyQuery.Active := false; MyQuery.Free; MyDataSource.Free;
end; |
mkinzler - Fr 09.07.10 11:10
Nimm mal verschiedene Query-Komponenten. Diese würde ich parametrisieren
jjturbo - Fr 09.07.10 11:20
Wie meinst Du das?
Aber das Problem scheint damit behoben zu sein, die Funktion wurde bis jetzt etwa 700 mal aufgerufen.
Muß man vor jedem ExecSQL Query.Active := false setzen? Bleibt sonst irgendetwas in den Tiefen der BDE geöffnet?
mkinzler - Fr 09.07.10 11:26
Es sieht ja wirklich danach aus
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!