Domanda

al lavoro abbiamo a che fare con diversi file mdb di MS Access, quindi utilizziamo il driver JdbcOdbcBridge predefinito fornito con Sun JVM e, nella maggior parte dei casi, funziona benissimo.

Il problema è che quando abbiamo a che fare con file più grandi, affrontiamo diverse volte eccezioni con il messaggio "Impossibile aprire altre tabelle". Come possiamo evitarlo?

Chiudiamo già tutte le nostre istanze di PreparedStatements e RecordSet e persino impostiamo le loro variabili su null, ma anche così questa eccezione continua a verificarsi. Cosa dovremmo fare? Come possiamo evitare queste brutte eccezioni? Qualcuno qui sa come?

Esiste una configurazione aggiuntiva per i driver ODBC su Windows che possiamo modificare per evitare questo problema?

È stato utile?

Soluzione

" Impossibile aprire altre tabelle " è un messaggio di errore migliore rispetto a " Impossibile aprire altri database, " che si riscontra più comunemente nella mia esperienza. In effetti, quest'ultimo messaggio quasi sempre maschera il primo.

Il motore di database Jet 4 ha un limite di 2048 tabella handle . Non mi è del tutto chiaro se questo sia simultaneo o cumulativo nella vita di una connessione. Ho sempre pensato che fosse cumulativo, poiché l'apertura di un minor numero di recordset alla volta nella pratica sembra consentire di evitare il problema.

Il problema è che " handle di tabella " non si riferisce solo agli handle di tabella, ma a qualcosa di molto più.

Prendi in considerazione un QueryDef salvato con questo SQL:

  SELECT tblInventory.* From tblInventory;

L'esecuzione di QueryDef utilizza DUE handle di tabella.

Cosa ?, potresti chiedere? Utilizza solo una tabella! Ma Jet utilizza un handle di tabella per il table e un handle di tabella per il QueryDef salvato.

Quindi, se hai un QueryDef come questo:

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

... se ciascuna delle tue query di origine contiene due tabelle, stai usando questi handle di tabella, uno per ciascuno:

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

Quindi, potresti pensare di avere solo quattro tabelle coinvolte (perché ci sono solo quattro tabelle di base), ma in realtà userai 7 tabelle handle per usare quelle 4 tabelle di base.

Se in un recordset, si utilizza quindi il QueryDef salvato che utilizza 7 handle di tabella, è stato utilizzato ancora un altro handle di tabella, per un totale di 8.

Nei tempi di Jet 3.5, la tabella originale gestiva la limitazione era 1024 e mi sono imbattuto in esso in una scadenza quando ho replicato il file di dati dopo aver progettato un'app funzionante. Il problema era che alcune delle tabelle di replica erano sempre aperte (forse per ogni recordset?) E che utilizzavano appena più handle di tabella per mettere l'app in cima.

Nel design originale di quell'app, stavo aprendo un sacco di forme pesanti con molte sottomaschere, caselle combinate e caselle di riepilogo, e in quel momento ho usato un sacco di QueryDef salvati per assemblare recordset standard che userei in molti luoghi (proprio come faresti con le visualizzazioni su qualsiasi database di server). Ciò che risolveva il problema era:

  1. caricando le sottomaschere solo quando sono state visualizzate.

  2. caricamento delle origini righe delle caselle combinate e delle caselle di riepilogo solo quando erano sullo schermo.

  3. eliminando tutti i QueryDef salvati e usando le istruzioni SQL che si univano alle tabelle non elaborate, ove possibile.

Questo mi ha permesso di distribuire quell'app nell'ufficio di Londra solo una settimana dopo il previsto. Quando è uscito Jet SP2, ha raddoppiato il numero di handle di tabella, che è quello che abbiamo ancora in Jet 4 (e, presumo, l'ACE).

In termini di utilizzo di Jet da Java tramite ODBC, il punto chiave sarebbe, penso:

  1. usa una singola connessione in tutta la tua app, piuttosto che aprirli e chiuderli secondo necessità (il che ti mette in pericolo di non riuscire a chiuderli).

  2. apri i recordset solo quando ne hai bisogno e ripulisci e rilascia le loro risorse quando hai finito.

Ora, potrebbe essere che ci siano perdite di memoria da qualche parte nella catena JDBC = > ODBC = > Jet dove pensi che stai rilasciando risorse e non vengono rilasciate affatto. Non ho alcun consiglio specifico su JDBC (in quanto non lo uso - dopo tutto sono un programmatore di Access), ma in VBA dobbiamo stare attenti a chiudere esplicitamente i nostri oggetti e rilasciare le loro strutture di memoria perché VBA utilizza il conteggio dei riferimenti e, a volte, non sa che è stato rilasciato un riferimento a un oggetto, quindi non rilascia la memoria per quell'oggetto quando esce dall'ambito.

Quindi, nel codice VBA, ogni volta che lo fai:

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

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

... dopo aver fatto ciò che devi fare, devi finire con questo:

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

... e questo anche se le variabili dichiarate non rientrano nell'ambito immediatamente dopo quel codice (che dovrebbe rilasciare tutta la memoria utilizzata da loro, ma non lo fa in modo affidabile al 100%).

Ora, non sto dicendo che questo è ciò che fai in Java, ma sto semplicemente suggerendo che se hai problemi e pensi di rilasciare tutte le tue risorse, forse devi determinare se ' a seconda della garbage collection per farlo e invece devi farlo esplicitamente.

Perdonami se avessi detto qualcosa di stupido riguardo Java e JDBC - Sto solo segnalando alcuni dei problemi che gli sviluppatori di Access hanno avuto nell'interazione con Jet (tramite DAO, non ODBC) che riportano lo stesso messaggio di errore che ricevi, nella speranza che la nostra esperienza e pratica possano suggerire una soluzione per il tuo particolare ambiente di programmazione.

Altri suggerimenti

Di recente ho provato UCanAccess - un driver JDBC java puro per MS Access. Dai un'occhiata: http://sourceforge.net/projects/ucanaccess/ - funziona anche su Linux; - ) Per caricare le librerie richieste, è necessario del tempo. Non l'ho ancora testato per scopi più che di sola lettura.

In ogni caso, ho riscontrato problemi come descritto sopra con sun.jdbc.odbc.JdbcOdbcDriver. Dopo aver aggiunto le istruzioni close () in seguito alla creazione di oggetti statement (e chiamate a executeUpdate su tali) nonché le istruzioni System.gc (), i messaggi di errore si sono interrotti ;-)

Esiste una possibilità esterna che stai semplicemente esaurendo le connessioni di rete gratuite. Abbiamo riscontrato questo problema su un sistema occupato al lavoro.

Qualcosa da notare è che le connessioni di rete, sebbene chiuse, potrebbero non rilasciare il socket fino al momento della garbage collection. Puoi verificarlo con NETSTAT / A / N / P TCP . Se hai molte connessioni nello stato TIME_WAIT , potresti provare a forzare una garbage collection alla chiusura delle connessioni o forse a intervalli regolari.

Dovresti anche chiudere l'oggetto Connection.

Anche cercare un'alternativa per il driver oddc jdbc sarebbe una buona idea. Non ho alcuna esperienza con un'alternativa, ma questo sarebbe un buon punto di partenza:

Esiste un'alternativa all'utilizzo di sun.jdbc .odbc.JdbcOdbcDriver?

Ho avuto lo stesso problema ma nessuna delle precedenti funzionava. Alla fine ho individuato il problema. Lo stavo usando per leggere il valore di un modulo da reinserire in una fonte record dell'elenco di ricerca.

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

Modificato in basso e funziona.

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

So che avrei dovuto scriverlo meglio, ma spero che questo aiuti qualcun altro nella stessa situazione.

Grazie Greg

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top