Frage

bei der Arbeit müssen wir mit mehreren MS Access MDB-Dateien umgehen, so verwenden wir den Standard JdbcOdbcBridge Treiber, die mit der Sun JVM kommt und, in den meisten Fällen, es funktioniert super.

Das Problem ist, dass, wenn wir mit einigen größeren Dateien zu tun haben, wir mehrmals Ausnahmen mit der Meldung „öffnen kann keine weiteren Tabellen“ stellen. Wie können wir das vermeiden?

Wir schließen bereits alle Instanzen PreparedStatements und Record und setzen sogar ihre Variablen auf null, aber auch so diese Ausnahme weiterhin passieren. Was sollen wir machen? Wie können wir diese fiesen Ausnahmen vermeiden? Hat jemand hier weiß, wie?

Gibt es eine zusätzliche Konfiguration der ODBC-Treiber in Windows, dass wir dieses Problem zu vermeiden ändern?

War es hilfreich?

Lösung

„Es können keine weiteren Tabellen geöffnet“ ist eine bessere Fehlermeldung als die „Kann keine weiteren Datenbanken öffnen“, die häufiger in meiner Erfahrung angetroffen wird. In der Tat ist, dass letztere Nachricht Maskieren fast immer das erstere.

Der Jet-Datenbank-Engine 4 hat ein Limit von 2048 Tabelle Griffen . Es ist nicht ganz klar für mich, ob dies innerhalb der Lebensdauer einer Verbindung gleichzeitig oder kumulativ. Ich habe immer davon ausgegangen, es ist kumulativ, da weniger Cord-Sets zu einer Zeit, in der Praxis zu öffnen scheint es möglich zu machen, um das Problem zu vermeiden.

Das Problem ist, dass „Tabelle behandelt“ bezieht sich nicht nur auf Tisch Griffe, sondern etwas viel.

Betrachten Sie eine gespeicherte QueryDef mit diesem SQL:

  SELECT tblInventory.* From tblInventory;

Ausführen, dass QueryDef verwendet zwei Tischgriffe.

Was ?, könnte man fragen? Es verwendet nur eine Tabelle! Aber Jet verwendet eine Tabelle Handle für den Tisch und einen Tisch Griff für die gespeicherte QueryDef.

Wenn Sie also eine QueryDef wie folgt aus:

  SELECT qryInventory.InventoryID, qryAuthor.AuthorName
  FROM qryInventory JOIN qryAuthor ON qryInventory.AuthorID = qryAuthor.AuthorID

... wenn jede Ihrer Quellenabfragen hat zwei Tabellen darin, verwenden Sie diese Tabelle Griffe, eine für jeden:

  Table 1 in qryInventory
  Table 2 in qryInventory
  qryInventory
  Table 1 in qryAuthor
  Table 2 in qryAuthor
  qryAuthor
  the top-level QueryDef

So, könnte man denken Sie nur vier Tabellen beteiligt sind (weil es nur vier Basistabellen sind), aber Sie werden tatsächlich 7 Tabelle Griffe werden mit , um diese vier Basistabellen zu verwenden.

Wenn in einem Re-Cord, Sie dann die gespeicherte QueryDef verwenden, die 7 Tabelle Griffe verwendet, haben Sie noch eine weitere Tabelle Griff verbraucht, für insgesamt 8.

Zurück in den Jet 3.5 Tage behandelt die ursprüngliche Tabelle Einschränkung war 1024, und ich stieß gegen sie auf einer Frist, wenn ich die Datendatei repliziert, nachdem eine Arbeits App zu gestalten. Das Problem war, dass einige der Replikationstabellen zu allen Zeiten geöffnet sind (vielleicht für jede Datensatzgruppe?), Und das verbrauchen gerade genug, um mehr Tisch übernimmt die App über die Spitze zu setzen.

In dem ursprünglichen Entwurf dieses App, ich war ein Bündel von Schwergewichts-Formen mit vielen subforms und Kombinationsfeldern und Listenfeldern zu öffnen, und zu diesem Zeitpunkt habe ich eine Menge gespeichert QueryDefs Standard-Cord-Sets vorzumontieren, die ich in verwenden würde, viele Orte (genau wie Sie mit Blick auf einem beliebigen Server-Datenbank würde). Was das Problem behoben war:

  1. Laden der subforms nur, wenn sie angezeigt wurden.

  2. Laden der rowsources der Kombinationsfelder und Listenfelder nur dann, wenn sie auf dem Bildschirm waren.

  3. immer von allen gespeicherten QueryDefs befreien und SQL-Anweisungen, die die rohen Tabellen verknüpft, wo immer möglich.

Das erlaubte mir, dass die App im Londoner Büro später nur noch eine Woche zu implementieren als geplant. Wenn Jet SP2 herauskommt, es die Anzahl der Tabellen Griffe verdoppelt, was ist das, was wir haben noch in Jet 4 (und ich nehme an, die ACE).

Im Hinblick auf die Verwendung von Jet aus Java über ODBC, würde der entscheidende Punkt sein, denke ich:

  1. eine einzige Verbindung in Ihrer App verwenden, anstatt zu öffnen und sie bei Bedarf zu schließen (die Sie in Gefahr läßt zu versagen, sie zu schließen).

  2. open-Cord-Sets nur dann, wenn man sie braucht, und aufzuräumen und ihre Ressourcen freigeben, wenn Sie fertig sind.

Nun könnte es sein, dass es Speicherlecks irgendwo in der JDBC => ODBC => Jet-Kette, wo man em <> denken Sie Ressourcen veröffentlichen und sie sind überhaupt nicht freigegeben zu werden. Ich habe keinen Rat spezifisch für JDBC (wie ich es nicht nutzen - ich bin ein Access-Programmierer, nachdem alle), aber in VBA haben wir ausdrücklich vorsichtig sein, über unsere Objekte zu schließen und veröffentlichen ihre Speicherstrukturen, weil VBA verwendet Referenzzählung, und manchmal weiß es nicht, dass ein Verweis auf ein Objekt freigegeben wurde, so dass es entbindet nicht den Speicher für das Objekt, wenn es außerhalb des Gültigkeitsbereiches geht.

Also, in VBA-Code, jedes Mal, wenn dies zu tun:

  Dim db As DAO.Database
  Dim rs As DAO.Recordset

  Set db = DBEngine(0).OpenDatabase("[database path/name]")
  Set rs = db.OpenRecordset("[SQL String]")

... nachdem Sie das getan haben, was Sie tun müssen, haben Sie damit beenden:

  rs.Close         ' closes the recordset
  Set rs = Nothing ' clears the pointer to the memory formerly used by it
  db.Close
  Set db = Nothing

... und das ist auch dann, wenn Ihre deklarierten Variablen außerhalb des Gültigkeitsbereichs gehen immediately nach diesem Code (die von ihnen benutzten den gesamten Speicher freigeben sollte, aber so 100% sicher nicht tun).

Nun, ich sage nicht, das ist, was Sie in Java zu tun, aber ich behaupte einfach, dass, wenn Sie Probleme haben und Sie denken, Sie alle Ihre Ressourcen sind Loslassen, vielleicht müssen Sie, wenn Sie bestimmen‘ re in Abhängigkeit von der Garbage collection, dies zu tun und stattdessen muß so explizit tun.

Verzeihen Sie mir, wenn ich gesagt habe, alles, was in Bezug auf Java und JDBC dumm - Ich berichte nur einige der Probleme, die Entwickler haben Zugriff hatte mit Jet in der Interaktion (via DAO, nicht ODBC), die gleich berichten Fehlermeldung, die Sie bekommen, in der Hoffnung, dass unsere Erfahrung und Praxis könnten eine Lösung für Ihre spezielle Programmierumgebung vor.

Andere Tipps

Vor kurzem habe ich versucht, UCanAccess - einen reinen Java-JDBC-Treiber für MS Access. Check out: http://sourceforge.net/projects/ucanaccess/ - läuft auf Linux zu; - ) Für die erforderlichen Bibliotheken laden, wird einige Zeit benötigt. Ich habe es nicht für mehr getestet als schreibgeschützt Zwecke noch.

Wie auch immer, ich Probleme erlebt, wie oben mit dem sun.jdbc.odbc.JdbcOdbcDriver beschrieben. Nach der Zugabe von close () Anweisungen nach Erstellung Erklärung Objekte (und fordert diejenigen executeUpdate) sowie System.gc () Aussagen, die Fehlermeldungen gestoppt; -)

Es gibt eine geringe Chance, dass Sie einfach aus freien Netzwerkverbindungen laufen. Wir hatten dieses Problem auf einem ausgelasteten System bei der Arbeit.

Etwas zu beachten ist, dass die Netzwerkverbindungen, obwohl geschlossen, die Steckdose nicht, bis die Garbage Collection Zeit freisetzen können. Sie können dies überprüfen, mit NETSTAT /A /N /P TCP. Wenn Sie eine Menge von Verbindungen im TIME_WAIT Zustand haben, könnten Sie versuchen, eine Garbage Collection auf Verbindung zwingen schließt oder vielleicht regelmäßige Abstände.

Sie sollten auch Ihr Connection-Objekt schließen.

in eine alternative Suche nach den jdbc-ODBC-Treiber wäre auch eine gute Idee sein. haben Sie keine Erfahrung mit mir andere Wahl, als dies ein guter Anfang wäre:

Gibt es eine Alternative zur Verwendung von sun.jdbc .odbc.JdbcOdbcDriver?

Ich hatte das gleiche Problem, aber keines der oben arbeitet. Ich locataed eventualy das Problem. Ich war mit dieser den Wert eines Formulars lesen zurück in eine Lookup-Liste Datenquelle zu setzen.

LocationCode = [Forms]![Support].[LocationCode].Column(2)
ContactCode = Forms("Support")("TakenFrom")

es an den unten geändert und es funktioniert.

LocationCode = Forms("Support")("LocationCode")
ContactCode = Forms("Support")("TakenFrom")

Ich weiß, ich hätte es besser geschrieben, aber ich hoffe, dass dies jemand anderes in der gleichen Situation hilft.

Danke Greg

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top