「これ以上テーブルを開くことができません」は、私の経験でより一般的に発生する「これ以上データベースを開くことができません」よりも優れたエラーメッセージです。実際、後者のメッセージはほとんどの場合前者を覆い隠しています。
Jet 4データベースエンジンには、2048個のテーブルハンドルの制限があります。これが接続の存続期間内で同時であるか累積的であるかは、私には完全には明らかではありません。実際には一度に開くレコードセットの数を減らすことで問題を回避できるように思われるため、これは累積的であると常に想定しています。
問題は、「テーブルハンドル」がテーブルハンドルを指すだけでなく、それ以上のものを指すことです。
次のSQLで保存されたQueryDefについて考えてみます。
SELECT tblInventory.* From tblInventory;
そのQueryDefを実行すると、2つのテーブルハンドルが使用されます。
何?、あなたは尋ねるかもしれませんか?1つのテーブルのみを使用します!ただし、Jetはテーブルにテーブルハンドルを使用し、保存されたQueryDefにテーブルハンドルを使用します。
したがって、次のようなQueryDefがある場合:
SELECT qryInventory.InventoryID, qryAuthor.AuthorName
FROM qryInventory JOIN qryAuthor ON qryInventory.AuthorID = qryAuthor.AuthorID
...各ソースクエリに2つのテーブルがある場合、次のテーブルハンドルを使用しています。
Table 1 in qryInventory
Table 2 in qryInventory
qryInventory
Table 1 in qryAuthor
Table 2 in qryAuthor
qryAuthor
the top-level QueryDef
したがって、(ベーステーブルが4つしかないため)テーブルが4つしかないように思われるかもしれませんが、実際には、これらの4つのベーステーブルを使用するために7つのテーブルハンドルを使用します。
レコードセットで、7つのテーブルハンドルを使用する保存済みのQueryDefを使用する場合、さらに別のテーブルハンドルを使用して、合計8つになります。
Jet 3.5の時代には、元のテーブルハンドルの制限は1024でしたが、動作するアプリを設計した後にデータファイルを複製したときに、期限にぶつかりました。問題は、一部のレプリケーションテーブルが常に開いていて(おそらく各レコードセットに対して?)、アプリを上に置くのに十分な数のテーブルハンドルを使い果たしてしまったことです。
そのアプリの元のデザインでは、たくさんのサブフォームとコンボボックスとリストボックスを備えた大量のフォームを開いていました。そのとき、多くの場所で使用する標準のレコードセットを事前に組み立てるために、保存されたQueryDefをたくさん使用しました(サーバーデータベースのビューの場合と同じように)。問題を解決したのは次のとおりです。
表示されたときにのみサブフォームをロードします。
コンボボックスとリストボックスの行ソースを、画面に表示されているときにのみロードします。
保存されているすべてのQueryDefを削除し、可能な限りrawテーブルに結合されたSQLステートメントを使用します。
これにより、予定より1週間遅れてロンドンのオフィスにそのアプリをデプロイすることができました。Jet SP2がリリースされたとき、テーブルハンドルの数は2倍になりました。これは、Jet 4(および、おそらくACE)にまだあるものです。
ODBCを介してJavaからJetを使用する場合、重要なポイントは次のようになります。
必要に応じて接続を開いたり閉じたりするのではなく、アプリ全体で単一の接続を使用します(これにより、接続を閉じられなくなる危険性があります)。
必要な場合にのみレコードセットを開き、完了したらリソースをクリーンアップして解放します。
ここで、JDBC => ODBC => Jetチェーンのどこかにメモリリークがあり、リソースを解放していると思われ、リソースがまったく解放されていない可能性があります。JDBCに固有のアドバイスはありません(使用しないため、結局はAccessプログラマーです)が、VBAでは、オブジェクトを明示的に閉じてメモリ構造を解放することに注意する必要があります。 VBAは参照カウントを使用し、オブジェクトへの参照が解放されたことを認識しない場合があるため、スコープ外になったときにそのオブジェクトのメモリを解放しません。
したがって、VBAコードでは、これを行うときはいつでも:
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = DBEngine(0).OpenDatabase("[database path/name]")
Set rs = db.OpenRecordset("[SQL String]")
...必要なことを行った後、これで終了する必要があります。
rs.Close ' closes the recordset
Set rs = Nothing ' clears the pointer to the memory formerly used by it
db.Close
Set db = Nothing
...そしてそれは、宣言された変数がそのコードの直後にスコープ外になった場合でもです(これにより、使用されているすべてのメモリが解放されますが、100%確実に解放されるわけではありません)。
さて、これがJavaで行っていることだと言っているのではありませんが、問題が発生していて、すべてのリソースを解放していると思われる場合は、依存しているかどうかを判断する必要があることを示唆しています。そうするためのガベージコレクションであり、代わりに明示的に行う必要があります。
JavaとJDBCに関して愚かなことを言ったら許してください-Access開発者が(ODBCではなくDAOを介して)Jetと対話する際に抱えていた同じエラーメッセージを報告する問題のいくつかを報告しています私たちの経験と実践があなたの特定のプログラミング環境のための解決策を示唆するかもしれないことを期待して、あなたは得ています。