MS Access - Больше не удается открыть ни одной таблицы

StackOverflow https://stackoverflow.com/questions/1807934

Вопрос

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

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

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

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

Это было полезно?

Решение

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

Ядро базы данных 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 для предварительной сборки стандартных наборов записей, которые я использовал бы в много мест (как и в случае с представлениями на любой базе данных сервера). Что решило проблему:

<Ол>
  • загрузка подчиненных форм только тогда, когда они были отображены.

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

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

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

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

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

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

  • Теперь может случиться так, что где-то в 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
    

    ... и это даже если ваши объявленные переменные выходят из области видимости сразу после этого кода (который должен

    Другие советы

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

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

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

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

    Вы также должны закрыть свой объект Connection.

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

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

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

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

    Изменил его на приведенный ниже, и он работает.

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

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

    Спасибо Грег

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top