Pergunta

no trabalho que temos de lidar com vários arquivos mdb do MS Access, por isso usamos o JdbcOdbcBridge driver padrão que vem com o Sun JVM e, na maioria dos casos, ele funciona muito bem.

O problema é que, quando temos que lidar com alguns arquivos maiores, enfrentamos várias vezes exceções com a mensagem "Não é possível abrir mais tabelas". Como podemos evitar isso?

Já feche todos os nossos casos de PreparedStatements e registros, e até mesmo definir suas variáveis ??como nulo, mas mesmo assim essa exceção continua a acontecer. O que deveríamos fazer? Como podemos evitar essas exceções desagradáveis? Alguém aqui sabe como?

Existe alguma configuração adicional para os drivers ODBC no Windows que podemos mudar para evitar este problema?

Foi útil?

Solução

"Não é possível abrir mais tabelas" é uma mensagem de erro melhor do que o "não é possível abrir mais bases de dados", que é mais comumente encontradas na minha experiência. Na verdade, esta última mensagem é quase sempre mascarando o primeiro.

O motor de banco de dados Jet 4 tem um limite de 2048 mesa alças . Não é totalmente claro para mim se isso é simultânea ou acumulada dentro da vida de uma conexão. Eu sempre assumi que é cumulativo, desde a abertura menos registros de cada vez, na prática parece torná-lo possível para evitar o problema.

O problema é que "pegas tabela" não se refere apenas a cabos de mesa, mas a algo muito mais.

Considere um QueryDef salvas com esse SQL:

  SELECT tblInventory.* From tblInventory;

Running que QueryDef usa duas alças de mesa.

O que ?, você pode perguntar? Ele usa apenas uma mesa! Mas Jet usa um identificador mesa para a mesa e uma alça de mesa para o QueryDef salvo.

Assim, se você tem um QueryDef como esta:

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

... se cada um de seus consultas de origem tem duas tabelas nele, você está usando essas alças de mesa, um para cada:

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

Assim, você pode pensar que tem apenas quatro mesas envolvidos (porque há apenas quatro mesas de base), mas você vai realmente estar usando 7 tabela alças , a fim de usar esses 4 tabelas base.

Se em um conjunto de registros, você, em seguida, usar o QueryDef salvo que usa 7 alças de mesa, você usou-se ainda uma outra alça mesa, para um total de 8.

Para trás nos Jet 3,5 dias, o original limitação alças de mesa era 1024, e eu colidido contra ele em um prazo quando eu duplicado o arquivo de dados depois de projetar um aplicativo de trabalho. O problema era que algumas das tabelas de replicação estão abertos em todos os momentos (talvez para cada conjunto de registros?), E que usou-se apenas o suficiente mais alças de mesa para colocar o aplicativo ao longo do topo.

No projeto original desse aplicativo, eu estava abrindo um monte de formas pesados ??com lotes de subformulários e caixas de combinação e caixas de listagem, e naquele tempo eu usei um monte de QueryDefs salvos em registros padrão preassemble que eu usaria em muitos lugares (como você faria com pontos de vista sobre qualquer base de dados do servidor). O que corrigiu o problema foi:

  1. carregando os subformulários apenas quando eles foram exibidos.

  2. carregando os rowsources das caixas de combinação e caixas de listagem somente quando eles estavam na tela.

  3. se livrar de todos os QueryDefs salvos e usando instruções SQL que se juntaram às mesas matérias, sempre que possível.

Isso me permitiu implantar esse aplicativo no escritório de Londres apenas uma semana depois do planejado. Quando Jet SP2 saiu, ele dobrou o número de identificadores de mesa, que é o que ainda temos no Jet 4 (e, presumo, a ACE).

Em termos de utilização Jet de Java via ODBC, o ponto chave seria, penso:

  1. usar uma única conexão em todo o seu aplicativo, em vez de abrir e fechar-los quando necessário (o que deixa em perigo de não fechá-los).

  2. registros abertos apenas quando você precisar deles, e até limpa e liberar seus recursos quando você está feito.

Agora, pode ser que haja vazamentos de memória em algum lugar na cadeia JDBC => ODBC => Jet onde pensar você está liberando recursos e eles não estão sendo liberados em tudo. Eu não tenho nenhum conselho específico para JDBC (como eu não usá-lo - Eu sou um programador Access, depois de tudo), mas em VBA temos que ter cuidado sobre o fechamento explicitamente nossos objetos e liberando suas estruturas de memória, porque VBA utiliza a contagem de referência, e às vezes não sabe que uma referência a um objeto foi lançado, para que ele não liberar a memória para esse objeto quando ele sai do escopo.

Assim, em código VBA, a qualquer hora que você faça o seguinte:

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

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

... depois de ter feito o que você precisa fazer, você tem que terminar com este:

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

... e que do mesmo se suas variáveis ??declaradas sair do ime escopomente após esse código (que deve liberar toda a memória usada por eles, mas não fazê-lo 100% confiável).

Agora, eu não estou dizendo que isso é o que você faz em Java, mas eu estou simplesmente sugerindo que, se você está tendo problemas e você acha que está liberando todos os seus recursos, talvez você precisa para determinar se você' re dependendo de coleta de lixo para fazê-lo e, em vez precisa fazê-lo explicitamente.

Perdoe-me se eu tivesse dito qualquer coisa que é estúpido em relação a Java e JDBC - Estou apenas relatando alguns dos problemas que os desenvolvedores de acesso tiveram em interagir com Jet (via DAO, não ODBC) que relatam o mesmo mensagem de erro que você está recebendo, na esperança de que a nossa experiência e prática pode sugerir uma solução para o seu ambiente de programação particular.

Outras dicas

Recentemente eu tentei UCanAccess - um java JDBC driver puro para MS Access. Confira: http://sourceforge.net/projects/ucanaccess/ - obras em Linux também; - ) Para carregar as bibliotecas necessárias, é necessário algum tempo. Eu não testei isso por mais de fins somente leitura ainda.

De qualquer forma, eu experimentei problemas como descrito acima com o sun.jdbc.odbc.JdbcOdbcDriver. Depois de adicionar close () declarações após a criação de objetos de instrução (e chamadas para executeUpdate sobre aqueles), bem como System.gc () declarações, as mensagens de erro parado; -)

Há uma chance fora que você está simplesmente ficar sem conexões de rede livres. Tivemos esse problema em um sistema ocupado no trabalho.

Algo a notar é que as conexões de rede, embora fechada, não pode liberar o soquete até que o tempo de coleta de lixo. Você pode verificar isso com NETSTAT /A /N /P TCP. Se você tem um monte de conexões no estado TIME_WAIT, você pode tentar forçar uma coleta de lixo na encerra conexão ou talvez intervalos regulares.

Você também deve fechar o objeto de conexão.

Olhando para uma alternativa para o driver ODBC jdbc também seria uma boa idéia. Não tenho nenhuma experiência com uma alternativa mim, mas isso seria um bom lugar para começar:

Existe uma alternativa ao uso sun.jdbc .odbc.JdbcOdbcDriver?

Eu tive o mesmo problema, mas nenhuma das opções acima estava trabalhando. I eventualy locataed a questão. Eu estava usando isso para ler o valor de um formulário para colocar de volta em uma fonte de lista de pesquisa de registro.

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

mudou para o baixo e ele funciona.

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

Eu sei que deveria ter escrito isso melhor, mas eu espero que isso ajude alguém na mesma situação.

Graças Greg

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top