MS Access - не могу открыть больше таблиц - PullRequest
6 голосов
/ 27 ноября 2009

на работе нам приходится иметь дело с несколькими файлами mdb MS Access, поэтому мы используем драйвер JdbcOdbcBridge по умолчанию, который поставляется с Sun JVM, и в большинстве случаев он прекрасно работает.

Проблема в том, что когда нам приходится иметь дело с некоторыми большими файлами, мы сталкиваемся с несколькими исключениями с сообщением «Не удается открыть больше таблиц». Как мы можем избежать этого?

Мы уже закрыли все наши экземпляры PreparedStatements и RecordSets и даже установили для их переменных значение null, но даже в этом случае это исключение продолжает происходить. Что нам делать? Как мы можем избежать этих неприятных исключений? Кто-нибудь здесь знает, как?

Есть ли какая-либо дополнительная конфигурация драйверов ODBC в Windows, которую мы можем изменить, чтобы избежать этой проблемы?

Ответы [ 5 ]

10 голосов
/ 28 ноября 2009

«Не удается открыть больше таблиц» - это лучшее сообщение об ошибке, чем «Не удается открыть больше баз данных», которое чаще встречается в моем опыте. Фактически, последнее сообщение почти всегда маскирует первое.

Ядро базы данных Jet 4 имеет ограничение в 2048 таблиц дескрипторов . Мне не совсем понятно, является ли это одновременным или накопительным в течение жизни соединения. Я всегда предполагал, что это кумулятивно, поскольку на практике открытие меньшего количества наборов записей одновременно позволяет избежать этой проблемы.

Проблема в том, что «дескрипторы таблиц» относятся не только к дескрипторам таблиц, но к чему-то гораздо большему.

Рассмотрим сохраненный QueryDef с этим SQL:

  SELECT tblInventory.* From tblInventory;

Запуск этого QueryDef использует ДВА дескриптора таблицы.

Что ?, спросите вы? Используется только одна таблица! Но Jet использует дескриптор таблицы для таблицы и дескриптор таблицы для сохраненного QueryDef.

Таким образом, если у вас есть QueryDef, как это:

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

... если в каждом из ваших исходных запросов есть две таблицы, вы используете эти дескрипторы таблиц, по одному для каждой:

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

Итак, вы можете подумать, что задействованы только четыре таблицы (потому что есть только четыре базовые таблицы), но вы на самом деле будете использовать 7 таблиц дескрипторы , чтобы использовать эти 4 базовые таблицы.

Если в наборе записей вы используете сохраненный QueryDef, который использует 7 дескрипторов таблиц, вы использовали еще один дескриптор таблицы, всего 8 *.

Еще в Jet 3.5 дней ограничение исходной обработки таблицы составляло 1024, и я столкнулся с ним в крайний срок, когда я реплицировал файл данных после разработки работающего приложения. Проблема заключалась в том, что некоторые из таблиц репликации были открыты всегда (возможно, для каждого набора записей?), И для этого потребовалось достаточно больше дескрипторов таблиц, чтобы приложение превысило все возможности.

В оригинальном дизайне этого приложения я открывал кучу тяжеловесных форм с множеством подчиненных форм, а также со списками и списками, и в то время я использовал множество сохраненных QueryDef для предварительной сборки стандартных наборов записей, которые я использовал бы в много мест (как и в случае с представлениями на любой базе данных сервера). Что решило проблему было:

  1. загрузка подчиненных форм только при их отображении.

  2. загрузка источников строк полей со списками и списков только тогда, когда они были на экране.

  3. избавление от всех сохраненных QueryDefs и использование операторов SQL, которые соединяли необработанные таблицы, где это возможно.

Это позволило мне развернуть это приложение в лондонском офисе только на одну неделю позже, чем планировалось. Когда вышел Jet SP2, он удвоил количество дескрипторов таблиц, что у нас все еще есть в Jet 4 (и, я полагаю, ACE).

С точки зрения использования Jet из Java через ODBC ключевым моментом, я думаю, будет:

  1. используйте одно соединение во всем приложении, а не открывайте и закрывайте их по мере необходимости (что может привести к невозможности их закрытия).

  2. открывать наборы записей только тогда, когда они вам нужны, очищать и освобождать их ресурсы, когда вы закончите.

Теперь может быть, что где-то есть утечки памяти в цепочке 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 при взаимодействии с Jet (через DAO, а не ODBC), которые сообщают об одном сообщение об ошибке, которое вы получаете, в надежде, что наш опыт и практика могут предложить решение для вашей конкретной среды программирования.

3 голосов
/ 14 октября 2014

Недавно я попробовал UCanAccess - чистый java JDBC-драйвер для MS Access. Проверьте: http://sourceforge.net/projects/ucanaccess/ - работает и в Linux ;-) Для загрузки необходимых библиотек требуется некоторое время. Я не проверял это больше для целей только для чтения.

Во всяком случае, у меня возникли проблемы, как описано выше с sun.jdbc.odbc.JdbcOdbcDriver. После добавления операторов close () после создания объектов операторов (и вызовов для них executeUpdate), а также операторов System.gc () сообщения об ошибках прекратились; -)

1 голос
/ 27 ноября 2009

Существует вероятность того, что у вас просто закончатся бесплатные сетевые подключения. У нас была эта проблема в загруженной системе на работе.

Следует отметить, что сетевые соединения, хотя и закрытые, могут не освобождать сокет до времени сбора мусора. Вы можете проверить это с помощью NETSTAT /A /N /P TCP. Если у вас много соединений в состоянии TIME_WAIT, вы можете попробовать принудительно собрать сборку мусора при закрытии соединения или, возможно, через регулярные интервалы.

0 голосов
/ 23 июня 2013

У меня была такая же проблема, но ничего из вышеперечисленного не работало. Я в конечном итоге обнаружил проблему. Я использовал это, чтобы прочитать значение формы и вернуть ее в источник записей списка поиска.

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

Изменил его на ниже, и он работает.

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

Я знаю, что должен был написать это лучше, но я надеюсь, что это поможет кому-то еще в такой же ситуации.

Спасибо Грег

0 голосов
/ 27 ноября 2009

Вы также должны закрыть свой объект подключения.

Хорошей идеей будет поиск альтернативы для драйвера jdbc odbc. У меня нет опыта работы с альтернативой, но это было бы хорошим началом:

Есть ли альтернатива использованию sun.jdbc.odbc.JdbcOdbcDriver?

...