Pregunta

En el trabajo, tenemos que lidiar con varios archivos mdb de MS Access, por lo que usamos el controlador JdbcOdbcBridge predeterminado que viene con Sun JVM y, en la mayoría de los casos, funciona muy bien.

El problema es que cuando tenemos que tratar con algunos archivos más grandes, nos enfrentamos varias veces con excepciones con el mensaje " No se pueden abrir más tablas " ;. ¿Cómo podemos evitar eso?

Ya cerramos todas nuestras instancias de PreparedStatements y RecordSets, e incluso establecemos sus variables en nulas, pero aún así esta excepción continúa ocurriendo. ¿Qué debemos hacer? ¿Cómo podemos evitar estas desagradables excepciones? ¿Alguien aquí sabe cómo?

¿Hay alguna configuración adicional para los controladores ODBC en Windows que podamos cambiar para evitar este problema?

¿Fue útil?

Solución

" No se pueden abrir más tablas " es un mensaje de error mejor que el de " No se pueden abrir más bases de datos, " que se encuentra más comúnmente en mi experiencia. De hecho, este último mensaje casi siempre enmascara al primero.

El motor de base de datos Jet 4 tiene un límite de 2048 tablas controladores . No me queda del todo claro si esto es simultáneo o acumulativo dentro de la vida de una conexión. Siempre he asumido que es acumulativo, ya que abrir menos conjuntos de registros a la vez en la práctica parece permitir evitar el problema.

El problema es que " manejadores de tabla " no solo hace referencia a los manejadores de tablas, sino a algo mucho más.

Considere un QueryDef guardado con este SQL:

  SELECT tblInventory.* From tblInventory;

La ejecución de ese QueryDef usa DOS manejadores de tabla.

¿Qué ?, podrías preguntar? ¡Solo usa una mesa! Pero Jet usa un controlador de tabla para la tabla y un controlador de tabla para el QueryDef guardado.

Por lo tanto, si tiene un QueryDef como este:

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

... si cada una de las consultas de origen tiene dos tablas, estás usando estos manejadores de tabla, uno para cada:

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

Entonces, podrías pensar que solo tienes cuatro tablas involucradas (porque solo hay cuatro tablas base), pero en realidad estarás usando 7 tablas manejadores para usar esas 4 tablas base.

Si está en un juego de registros, entonces usa el QueryDef guardado que usa 7 manejadores de tabla, ha usado otro manejador de tabla, para un total de 8.

De vuelta en el Jet 3.5 días, la limitación de los manejadores de la tabla original era de 1024, y me topé con ella en una fecha límite cuando repetí el archivo de datos después de diseñar una aplicación que funcionaba. El problema fue que algunas de las tablas de replicación están abiertas en todo momento (¿quizás para cada conjunto de registros?), Y eso usó solo más controladores de tabla para colocar la aplicación en la parte superior.

En el diseño original de esa aplicación, estaba abriendo un montón de formularios pesados ??con muchos subformularios, cuadros combinados y cuadros de lista, y en ese momento utilicé muchos QueryDefs guardados para armar conjuntos de registros estándar que usaría en muchos lugares (al igual que lo haría con las vistas en cualquier base de datos del servidor). Lo que solucionó el problema fue:

  1. cargar los subformularios solo cuando se mostraron.

  2. cargando las fuentes de las filas de los cuadros combinados y cuadros de lista solo cuando estaban en pantalla.

  3. deshacerse de todos los QueryDefs guardados y usar sentencias SQL que se unieron a las tablas sin procesar, siempre que sea posible.

Esto me permitió implementar esa aplicación en la oficina de Londres solo una semana después de lo planeado. Cuando salió Jet SP2, duplicó el número de manejadores de tablas, que es lo que todavía tenemos en Jet 4 (y, supongo, ACE).

En cuanto al uso de Jet desde Java a través de ODBC, el punto clave sería, creo:

  1. use una sola conexión a través de su aplicación, en lugar de abrirlas y cerrarlas según sea necesario (lo que lo deja en peligro de no cerrarlas).

  2. abre los conjuntos de registros solo cuando los necesites, y limpia y libera sus recursos cuando hayas terminado.

Ahora, podría ser que haya fugas de memoria en algún lugar de la cadena JDBC = > ODBC = > donde piensas estás liberando recursos y no se están liberando en absoluto. No tengo ningún consejo específico para JDBC (ya que no lo uso; después de todo, soy programador de Access), pero en VBA tenemos que tener cuidado al cerrar explícitamente nuestros objetos y liberar sus estructuras de memoria porque VBA utiliza el recuento de referencias y, a veces, no sabe que se ha liberado una referencia a un objeto, por lo que no libera la memoria para ese objeto cuando está fuera del alcance.

Entonces, en el código VBA, cada vez que haga esto:

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

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

... después de haber hecho lo que tienes que hacer, debes terminar con esto:

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

... y eso es incluso si sus variables declaradas quedan fuera del alcance inmediatamente después de ese código (lo que debería liberar toda la memoria utilizada por ellas, pero no lo hace de manera 100% confiable).

Ahora, no estoy diciendo que esto sea lo que haces en Java, pero simplemente sugiero que si tienes problemas y crees que estás liberando todos tus recursos, tal vez necesites determinar si Dependiendo de la recolección de basura, debe hacerlo y, en su lugar, hacerlo explícitamente.

Perdóneme si hubiera dicho algo estúpido con respecto a Java y JDBC. Solo informo sobre algunos de los problemas que los desarrolladores de Access han tenido al interactuar con Jet (a través de DAO, no ODBC) que informan lo mismo. mensaje de error que está recibiendo, con la esperanza de que nuestra experiencia y práctica puedan sugerir una solución para su entorno de programación en particular.

Otros consejos

Recientemente probé UCanAccess, un controlador JDBC de Java puro para MS Access. Echa un vistazo a: http://sourceforge.net/projects/ucanaccess/ - también funciona en Linux; ) Para cargar las bibliotecas requeridas, se necesita algo de tiempo. Todavía no lo he probado con fines más que de solo lectura.

De todos modos, experimenté problemas como los descritos anteriormente con sun.jdbc.odbc.JdbcOdbcDriver. Después de agregar sentencias close () luego de la creación de objetos de sentencia (y llamadas a executeUpdate en ellos) así como sentencias System.gc (), los mensajes de error se detuvieron ;-)

Existe la posibilidad de que simplemente te estés quedando sin conexiones de red gratuitas. Tuvimos este problema en un sistema ocupado en el trabajo.

Algo a tener en cuenta es que las conexiones de red, aunque están cerradas, no pueden liberar el socket hasta el momento de la recolección de basura. Puede verificar esto con NETSTAT / A / N / P TCP . Si tiene muchas conexiones en el estado TIME_WAIT , podría intentar forzar una recolección de basura en el cierre de la conexión o tal vez en intervalos regulares.

También debes cerrar tu objeto Connection.

También sería una buena idea buscar una alternativa para el controlador jdbc odbc. No tengo experiencia con una alternativa, pero este sería un buen lugar para comenzar:

¿Existe alguna alternativa a usar sun.jdbc? .odbc.JdbcOdbcDriver?

Tuve el mismo problema pero ninguno de los anteriores funcionaba. Eventualmente localicé el problema. Estaba usando esto para leer el valor de un formulario para volver a colocarlo en una fuente de registro de la lista de búsqueda.

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

Lo cambié a la siguiente y funciona.

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

Sé que debería haberlo escrito mejor, pero espero que esto ayude a alguien más en la misma situación.

Gracias Greg

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top