Categorias → JDBC
Grails: resolvendo o problema de queda de conexão com o MySQL
Você que trabalha com Grails e MySQL já topou com excessões como estas: “com.mysql.jdbc.CommunicationsException: Communications link failure“, “java.net.SocketException: Broken pipe” , “java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.” ?
Normalmente ocorrem após algumas horas de inatividade da sua aplicação. Normalmente acontecem porquê o MySQL fecha as conexões inativas, algumas das quais eram justamente as do seu projeto. Há duas soluções para o problema: uma porca e outra elegante.
A porca é simplesmente não fazer nada: ao mandar recarregar novamente a página será recriada a conexão com o MySQL e parecerá que o problema foi resolvido.
A elegante é alterar a seção dataSource do arquivo grails-app/conf/DataSource.groovy para que fique parecido com o exemplo abaixo:
dataSource {
pooled = true
driverClassName = "com.mysql.jdbc.Driver"
username = "seu_usuario"
password = "sua_senha"
properties {
maxActive = 50
maxIdle = 25
minIdle = 5
initialSize = 5
minEvictableIdleTimeMillis = 60000
timeBetweenEvictionRunsMillis = 60000
maxWait = 10000
validationQuery = "/* ping */"
}
}
A diferença é a seção properties. Nela basta incluir as configurações do pool de conexões do Hibernate. Por deafult, o Hibernate utiliza como gerenciador de pool de conexões o C3P0 que, por sua vez, evita que você obtenha uma conexão inválida com o banco de dados.
Agora, explicando os parâmetros:
maxActive: número máximo de conexões abertas e ativas com o SGBD
maxIdle: número máximo de conexões em stand by que você quer manter
initialSize: número inicial de conexões com o banco de dados
minEvictableIdleTimeMillis: tempo mínimo em milisegundos para que o pool de conexões comece a fechar conexões em idle
timeBetweenEvictionRunsMillis: o tempo entre as limpezas de conexão em milisegundos
maxWait: tempo máximo de espera em milisegundos para se obter uma conexão ou de espera de resultado de uma conexão
validationQuery: qualquer comando a ser enviado para o SGBD apenas para verificar se a conexão está válida ou não.
E é isto: agora seus usuários (e você) não verão mais aquela maldita mensagem de erro ao acessar seu sistema pela manhã
Outra causa para o maldito erro “Não é possível abrir mais tabelas” do MS Access com JDBC ODBC Bridge!
Como sempre, o Access apronta das suas comigo. Quando achava que já tinha resolvido todos os problemas relacionados ao maldito problema “Não é possível abrir mais tabelas” (veja este link), encontrei outra possível causa para o mesmo no StackOverflow.
O que pode ocorrer é o seguinte: há situações nas quais o seu cliente pode perder conexões com a rede. Quando a conexão é fechada, não necessáriamente é liberado o socket de conexão com os arquivos de conexão com o Access até que seja executado o coletor de lixo do Java.
Ou seja: você fecha a sua conexão, assim como todas as suas instâncias de PreparedStatements e ResultSets, define-as como null mas o driver ainda não as fechou porque perdeu conexão com a rede momentaneamente.
Como picos de rede são comuns em ambientes mais complexos (e não tão complexos assim), a solução é a seguinte: ao trabalhar com Access e Java, execute o garbage colector de tempos em tempos para garantir que as conexões fechadas e nulificadas sejam de fato fechadas no driver ODBC.
A minha pergunta relacionada no StackOverflow pode ser vista aqui com ainda mais detalhes.
Link útil: acessando bases de dados MS Access com Java
Sempre enrolei pra escrever um post assim, até que encontrei um pronto na internet.
Sendo assim, se você também sofre tendo de acessar o maldito Access usando Java, recomendo que leia o guia abaixo: muito útil.
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=2691&lngWId=2#SECTION0
Grails e código legado – rejuvenesça seu código legado!!!
Um dos aspectos mais fenomenais do Grails consiste no reaproveitamento de código legado. É muito bacana ter todo o ganho de produtividade que o framework nos oferece, no entanto, este ganho só se torna REAL com reaproveitamento de código. E é neste ponto que Grails se torna REALMENTE interessante para o desenvolvedor que trabalha com Java.
Nesta semana precisei criar uma nova aplicação web que, na realidade, não passava de uma interface para um sistema legado. O que eu tinha então: todos os jars que compunham a aplicação e uma escolha a fazer: qual framework utilizar: JSF, Struts, apenas servlets (um momento de insanidade, concordo)?
Iniciei com JSF. Criei a aplicação no Netbeans, inclui no projeto todos os arquivos jar que precisava (inúmeros: inclua ai todos os arquivos de dependência do Spring + Hibernate e saberá do que estou falando) e comecei o trabalho. Momentos depois, a aplicação começou a dar problemas: o Tomcat havia começado a “implicar” com meu arquivo de configuração do faces, o que me deu MUITA preguiça. Foi quando algo me veio à cabeça: uma aplicação feita em Grails não precisa ter classes de domínio!
Sendo assim, criei uma nova aplicação feita em Grails e, ao invés de utilizá-lo como um stack completo, o que costuma ser feito na maior parte das vezes, optei por trabalhar apenas com os controladores. E não é que deu certo?
O procedimento que segui foi basicamente o seguinte:
1. Criar um novo projeto Grails e, em seguida, anular as configurações de acesso a base de dados.
Neste ponto: a única ação necessária a fazer consiste em editar o seu arquivo DataSource.groovy para que fique exatamente como o descrito abaixo:
dataSource {
}
hibernate {
}
// environment specific settings
environments {
development {
dataSource {
}
}
test {
dataSource {
}
}
production {
dataSource {
}
}
}
Importante: a alteração deste arquivo de configuração é opcional. No entanto, é uma boa idéia alterá-lo, pois você não irá precisar do HSQLDB rodando a toa por trás dos panos, não é mesmo?
2. Copie todos os seus arquivos .jar que você necessite para dentro do diretório lib de sua aplicação
Neste caso, por arquivos .jar, deve ser entendido o seu código legado e suas dependências. E ai é que a coisa fica interessante: como Grails já vêm com o stack completo, você basicamente só precisará incluir neste diretório, além do seu código legado, uma ou outra biblioteca que sua aplicação venha a utilizar.
Caso sua aplicação utilize algum dos frameworks abaixo, você nem sequer precisará copiar os arquivos jar necessários para dentro do diretório lib. Na realidade, para evitar conflitos, é ideal que você não os copie. Muito bem: vamos a lista dos frameworks:
Sitemesh, Hibernate, Sprng, Log4J, JUnit, Ant, Commons (boa parte do Apache Commons já vem com o Grails), Xalan, Xerces, Hsqldb.
Como pode ser visto, a quantidade de arquivos de dependência com os quais você venha a se preocupar diminui bastante neste momento. No meu caso, só precisei copiar o driver JDBC para o MySQL e o jar do JExcel (além, é claro, do meu código legado).
Dica: navegue pelo diretório lib da sua instalação do Grails. Você perceberá que talvez eu não tenha mencionado todas as bibliotecas que o Grails utiliza!
3. Não tem passo 3!!!
Finalizado este processo, tudo o que você precisa fazer daqui pra frente irá consistir em trabalhar apenas com os controladores de sua aplicação, que deverão, por sua vez, acessar diretamente seu código legado, e pronto: você terá reaproveitado 100% do seu código e ainda terá tido no final das contas um ganho de produtividade gigantesco usando apenas a parte dos controladores do Grails!
A grande dica para a finalização de sua aplicação é a seguinte: esqueça o GORM!
Vantagens com relação aos demais frameworks
Nesta experiência, ficaram nítidas para mim algumas vantagens desta abordagem com relação ao procedimento tomado até então, que consistia em utilizar um framework mais tradicional como JSF ou Struts. Seguem as vantagens que observei:
- Reaproveitamento total de código legado: reparem que em momento algum precisei recompilar coisa alguma. Lidei aqui apenas com as camadas de visualização e controle.
- Sem arquivos de configuração. Já sofreu com o maldito arquivo de configuração do JSF ou Struts? Já penou com o web.xml? No caso do Grails, eu nem sequer me lembro de configurar qualquer coisa que não seja o acesso a dados!
- Rejuvenescimento do código legado: há momentos nos quais olho para o meu código Java e, em seguida, ao olhar para o meu código Groovy, tenho a impressão de que o mesmo encontra-se velho.
Ao trabalhar com Grails, estou utilizando código Groovy para acessar meu código Java.
Se assim como eu você também já está um pouco entediado em codificar na lingua mãe, Grails cai como uma luva. - Facilidade de deploy: como não preciso me preocupar com tantos arquivos .jar, os meus problemas de deploy práticamente acabaram. Basta executar grails war e pronto. Lá está o war que precisava!
- Controladores realmente simples. Basta se lembrar do código que você escreve usando JSF ou Struts pra ver a diferença. No caso do Grails, é realmente simples: sem mapeamentos, sem regras: apenas closures simples relacionadas a arquivos de visualização igualmente simples.
- Filtros simples! Nada de implementar ou extender classes ou alterar arquivos de configuração!
- É Grails! Este para mim é o ponto mais importante: eu tenho todo o ganho de produtividade do Grails com meu código legado!
E aqui entra uma conclusão paradoxal: Grails sem o GORM acessando seu código fonte legado é ainda mais poderoso do que com o GORM. Por que isto? Simples: porque o reaproveitamento de código Grails não é a coisa mais simples do mundo. Se você cria por exemplo uma aplicação A em Grails, e em seguida quer reaproveitar parte do seu código em um projeto B, as coisas já se complicam. No entanto, se você tem sua camada de negócio bem organizada, reaproveitá-la no Grails é simples!
Como o MALDITO Access pode jogar uma JVM no chão
Este problema ocorre com as versões 5 e 6 do Java executando no sistema operacional Windows XP.
Recentemente enfrentamos um problema bastante interessante: ao instanciarmos um objeto do tipo PreparedStatement (usando como conexão a ponte JdbcOdbc padrão do Java) acessando uma base de dados Access (97), a JVM simplesmente ia pro chão. BOOM!
O erro só aparece no Windows XP, enquanto no Vista, as coisas eram executadas sem dificuldade. Como consequencia, ao analisarmos o log de crash da JVM, acabamos por perceber que o erro não era em nossa aplicação, mas sim nos drivers ODBC (vide log abaixo). Era incrível: bastava instanciar o preparedstatement no XP e… BOOM.
Analisando mais o nosso código, descobrimos o que estava dando errado. Só para simplificar o código era algo mais ou menos assim:
Connection conexao = metodoQueRetornaAConexaoComMalditoAccess97();
// bla bla bla
PreparedStatement stmt = conexao.prepareStatement("select * from tabelaMaldita"); // Aqui rolava o boom da JVM
Analisando o código, descobrimos que, no meio de “blablabla”, devido a um erro de programação, a conexão era fechada. Sendo assim, ao instanciar um novo PreparedStatement, com a mesma, o que você espera? Que seja disparada uma excessão, correto? Errado! No caso do Access 97 executando no XP (driver do Microsoft Access versão 4.0.0) ele simplesmente quebra a JVM, finalizando o processo.
Segue abaixo o log básico para aqueles que vierem a passar por esta desagradável situação:
# # An unexpected error has been detected by Java Runtime Environment: # # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x7c90100b, pid=2616, tid=948 # # Java VM: Java HotSpot(TM) Client VM (11.0-b16 mixed mode, sharing windows-x86) # Problematic frame: # C [ntdll.dll+0x100b] # # If you would like to submit a bug report, please visit: # http://java.sun.com/webapps/bugreport/crash.jsp # The crash happened outside the Java Virtual Machine in native code. # See problematic frame for where to report the bug. # --------------- T H R E A D --------------- Current thread (0x03402800): JavaThread "Thread-9" [_thread_in_native, id=948, stack(0x046c0000,0x04710000)] siginfo: ExceptionCode=0xc0000005, reading address 0x00000018 Registers: EAX=0x00000004, EBX=0x27130be0, ECX=0x7ffa5000, EDX=0x00000004 ESP=0x0470f7b8, EBP=0x0470f7d0, ESI=0x00000000, EDI=0x039d1348 EIP=0x7c90100b, EFLAGS=0x00010202 Top of Stack: (sp=0x0470f7b8) 0x0470f7b8: 746459fa 00000004 039d1374 7461139f 0x0470f7c8: 039d1374 039d1348 0470f7e0 74620b2a 0x0470f7d8: 039d1374 03402914 0470f7f4 7461822b 0x0470f7e8: 039d1348 74640000 00000000 0470f810 0x0470f7f8: 74619652 039d1348 0470f830 00000003 0x0470f808: 03fd9548 03402914 0470f828 6d36124e 0x0470f818: 039d1348 0470f830 03402800 27130be0 0x0470f828: 0470f870 00929cf1 00000000 0470f88c Instructions: (pc=0x7c90100b) 0x7c900ffb: 00 00 00 00 00 64 8b 0d 18 00 00 00 8b 54 24 04 0x7c90100b: 83 7a 14 00 75 4f f0 ff 42 04 75 19 8b 41 24 89 Stack: [0x046c0000,0x04710000], sp=0x0470f7b8, free space=317k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) C [ntdll.dll+0x100b] C [ODBC32.dll+0x10b2a] C [ODBC32.dll+0x822b] C [ODBC32.dll+0x9652] C [JdbcOdbc.dll+0x124e] j sun.jdbc.odbc.JdbcOdbc.allocStmt(J[B)J+0 j sun.jdbc.odbc.JdbcOdbc.SQLAllocStmt(J)J+47 j sun.jdbc.odbc.JdbcOdbcConnection.prepareStatement(Ljava/lang/String;II)Ljava/sql/PreparedStatement;+55 j sun.jdbc.odbc.JdbcOdbcConnection.prepareStatement(Ljava/lang/String;)Ljava/sql/PreparedStatement;+8 j ecm.legado.capex.importadorppex.Importador.importarTabCapex(Ljava/util/List;)V+135 j ecm.legado.capex.importadorppex.Importador.importar(Ljava/util/List;Ljava/io/File;)V+46 j ecm.legado.capex.swing.FImportadorPQ$7.run()V+212 v ~StubRoutines::call_stub Java frames: (J=compiled Java code, j=interpreted, Vv=VM code) j sun.jdbc.odbc.JdbcOdbc.allocStmt(J[B)J+0 j sun.jdbc.odbc.JdbcOdbc.SQLAllocStmt(J)J+47 j sun.jdbc.odbc.JdbcOdbcConnection.prepareStatement(Ljava/lang/String;II)Ljava/sql/PreparedStatement;+55 j sun.jdbc.odbc.JdbcOdbcConnection.prepareStatement(Ljava/lang/String;)Ljava/sql/PreparedStatement;+8 j ecm.legado.capex.importadorppex.Importador.importarTabCapex(Ljava/util/List;)V+135 j ecm.legado.capex.importadorppex.Importador.importar(Ljava/util/List;Ljava/io/File;)V+46 j ecm.legado.capex.swing.FImportadorPQ$7.run()V+212 v ~StubRoutines::call_stub --------------- P R O C E S S --------------- Java Threads: ( => current thread ) =>0x03402800 JavaThread "Thread-9" [_thread_in_native, id=948, stack(0x046c0000,0x04710000)] 0x03316800 JavaThread "ElementEventQueue.QProcessor-1" daemon [_thread_blocked, id=1096, stack(0x03980000,0x039d0000)] 0x0340e800 JavaThread "Swing-Shell" daemon [_thread_blocked, id=2792, stack(0x03ac0000,0x03b10000)] 0x02b77800 JavaThread "com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2" daemon [_thread_blocked, id=2232, stack(0x03930000,0x03980000)] 0x033bd800 JavaThread "com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1" daemon [_thread_blocked, id=3500, stack(0x038e0000,0x03930000)] 0x02b80000 JavaThread "com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0" daemon [_thread_blocked, id=864, stack(0x03890000,0x038e0000)] 0x03300000 JavaThread "Timer-0" daemon [_thread_blocked, id=4000, stack(0x03840000,0x03890000)] 0x032ad800 JavaThread "MySQL Statement Cancellation Timer" daemon [_thread_blocked, id=2768, stack(0x037f0000,0x03840000)] 0x0326b800 JavaThread "TimerQueue" daemon [_thread_blocked, id=1676, stack(0x03720000,0x03770000)] 0x003a7400 JavaThread "DestroyJavaVM" [_thread_blocked, id=1892, stack(0x008c0000,0x00910000)] 0x03219c00 JavaThread "AWT-EventQueue-0" [_thread_blocked, id=3444, stack(0x03600000,0x03650000)] 0x02bdc400 JavaThread "AWT-Windows" daemon [_thread_in_native, id=1720, stack(0x03570000,0x035c0000)] 0x031d4400 JavaThread "AWT-Shutdown" [_thread_blocked, id=2628, stack(0x03520000,0x03570000)] 0x03211000 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=3648, stack(0x034d0000,0x03520000)] 0x02b52400 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=3440, stack(0x02e00000,0x02e50000)] 0x02b4c000 JavaThread "CompilerThread0" daemon [_thread_blocked, id=996, stack(0x02db0000,0x02e00000)] 0x02b4a800 JavaThread "Attach Listener" daemon [_thread_blocked, id=3000, stack(0x02d60000,0x02db0000)] 0x02b49400 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=964, stack(0x02d10000,0x02d60000)] 0x02b44400 JavaThread "Finalizer" daemon [_thread_blocked, id=3464, stack(0x02cc0000,0x02d10000)] 0x02b3fc00 JavaThread "Reference Handler" daemon [_thread_blocked, id=1996, stack(0x02c70000,0x02cc0000)] Other Threads: 0x02b3e000 VMThread [stack: 0x02c20000,0x02c70000] [id=3920] 0x02b6e000 WatcherThread [stack: 0x02e50000,0x02ea0000] [id=3560] VM state:not at safepoint (normal execution) VM Mutex/Monitor currently owned by a thread: None Heap def new generation total 18176K, used 437K [0x169a0000, 0x17d50000, 0x17d50000) eden space 16192K, 2% used [0x169a0000, 0x16a0d5f0, 0x17970000) from space 1984K, 0% used [0x17b60000, 0x17b60000, 0x17d50000) to space 1984K, 0% used [0x17970000, 0x17970000, 0x17b60000) tenured generation total 241984K, used 11457K [0x17d50000, 0x269a0000, 0x269a0000) the space 241984K, 4% used [0x17d50000, 0x18880580, 0x18880600, 0x269a0000) compacting perm gen total 17408K, used 17398K [0x269a0000, 0x27aa0000, 0x2a9a0000) the space 17408K, 99% used [0x269a0000, 0x27a9d978, 0x27a9da00, 0x27aa0000) ro space 8192K, 63% used [0x2a9a0000, 0x2aeb3ae8, 0x2aeb3c00, 0x2b1a0000) rw space 12288K, 53% used [0x2b1a0000, 0x2b8083f8, 0x2b808400, 0x2bda0000) Dynamic libraries: 0x00400000 - 0x00424000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\javaw.exe 0x7c900000 - 0x7c9b3000 <span> </span>C:\WINDOWS\system32\ntdll.dll 0x7c800000 - 0x7c900000 <span> </span>C:\WINDOWS\system32\kernel32.dll 0x77f50000 - 0x77ffb000 <span> </span>C:\WINDOWS\system32\ADVAPI32.dll 0x77db0000 - 0x77e42000 <span> </span>C:\WINDOWS\system32\RPCRT4.dll 0x77f20000 - 0x77f31000 <span> </span>C:\WINDOWS\system32\Secur32.dll 0x7e360000 - 0x7e3f1000 <span> </span>C:\WINDOWS\system32\USER32.dll 0x77e50000 - 0x77e99000 <span> </span>C:\WINDOWS\system32\GDI32.dll 0x76360000 - 0x7637d000 <span> </span>C:\WINDOWS\system32\IMM32.DLL 0x7c340000 - 0x7c396000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\msvcr71.dll 0x6d800000 - 0x6da56000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\client\jvm.dll 0x76b20000 - 0x76b4e000 <span> </span>C:\WINDOWS\system32\WINMM.dll 0x5df40000 - 0x5df48000 <span> </span>C:\WINDOWS\system32\rdpsnd.dll 0x76330000 - 0x76340000 <span> </span>C:\WINDOWS\system32\WINSTA.dll 0x5bcb0000 - 0x5bd05000 <span> </span>C:\WINDOWS\system32\NETAPI32.dll 0x77bf0000 - 0x77c48000 <span> </span>C:\WINDOWS\system32\msvcrt.dll 0x76bd0000 - 0x76bdb000 <span> </span>C:\WINDOWS\system32\PSAPI.DLL 0x6d280000 - 0x6d288000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\hpi.dll 0x6d7b0000 - 0x6d7bc000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\verify.dll 0x6d320000 - 0x6d33f000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\java.dll 0x6d7f0000 - 0x6d7ff000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\zip.dll 0x6d000000 - 0x6d138000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\awt.dll 0x72fb0000 - 0x72fd6000 <span> </span>C:\WINDOWS\system32\WINSPOOL.DRV 0x774c0000 - 0x775fd000 <span> </span>C:\WINDOWS\system32\ole32.dll 0x773b0000 - 0x774b3000 <span> </span>C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.5512_x-ww_35d4ce83\comctl32.dll 0x77ea0000 - 0x77f16000 <span> </span>C:\WINDOWS\system32\SHLWAPI.dll 0x746e0000 - 0x7472c000 <span> </span>C:\WINDOWS\system32\MSCTF.dll 0x75290000 - 0x752be000 <span> </span>C:\WINDOWS\system32\msctfime.ime 0x6d220000 - 0x6d274000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\fontmanager.dll 0x7c9c0000 - 0x7d1de000 <span> </span>C:\WINDOWS\system32\shell32.dll 0x6d610000 - 0x6d623000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\net.dll 0x71a70000 - 0x71a87000 <span> </span>C:\WINDOWS\system32\WS2_32.dll 0x71a60000 - 0x71a68000 <span> </span>C:\WINDOWS\system32\WS2HELP.dll 0x6d630000 - 0x6d639000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\nio.dll 0x10000000 - 0x1000c000 <span> </span>C:\Arquivos de programas\VMware\VMware Tools\hook.dll 0x6d190000 - 0x6d1b3000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\dcpr.dll 0x77100000 - 0x7718b000 <span> </span>C:\WINDOWS\system32\OLEAUT32.DLL 0x71a10000 - 0x71a50000 <span> </span>C:\WINDOWS\system32\mswsock.dll 0x60b30000 - 0x60b88000 <span> </span>C:\WINDOWS\system32\hnetcfg.dll 0x71a50000 - 0x71a58000 <span> </span>C:\WINDOWS\System32\wshtcpip.dll 0x76f00000 - 0x76f27000 <span> </span>C:\WINDOWS\system32\DNSAPI.dll 0x76f90000 - 0x76f98000 <span> </span>C:\WINDOWS\System32\winrnr.dll 0x76f40000 - 0x76f6d000 <span> </span>C:\WINDOWS\system32\WLDAP32.dll 0x76fa0000 - 0x76fa6000 <span> </span>C:\WINDOWS\system32\rasadhlp.dll 0x68000000 - 0x68036000 <span> </span>C:\WINDOWS\system32\rsaenh.dll 0x769a0000 - 0x76a55000 <span> </span>C:\WINDOWS\system32\USERENV.dll 0x6d560000 - 0x6d569000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\management.dll 0x03b10000 - 0x03de0000 <span> </span>C:\WINDOWS\system32\xpsp2res.dll 0x71ae0000 - 0x71af2000 <span> </span>C:\WINDOWS\system32\MPR.dll 0x75f30000 - 0x75f37000 <span> </span>C:\WINDOWS\System32\drprov.dll 0x71be0000 - 0x71bee000 <span> </span>C:\WINDOWS\System32\ntlanman.dll 0x71ca0000 - 0x71cb7000 <span> </span>C:\WINDOWS\System32\NETUI0.dll 0x71c60000 - 0x71ca0000 <span> </span>C:\WINDOWS\System32\NETUI1.dll 0x71c50000 - 0x71c57000 <span> </span>C:\WINDOWS\System32\NETRAP.dll 0x71bc0000 - 0x71bd3000 <span> </span>C:\WINDOWS\System32\SAMLIB.dll 0x75f40000 - 0x75f4a000 <span> </span>C:\WINDOWS\System32\davclnt.dll 0x77900000 - 0x779f5000 <span> </span>C:\WINDOWS\system32\SETUPAPI.dll 0x76fb0000 - 0x7702f000 <span> </span>C:\WINDOWS\system32\CLBCATQ.DLL 0x77030000 - 0x770fd000 <span> </span>C:\WINDOWS\system32\COMRes.dll 0x77be0000 - 0x77be8000 <span> </span>C:\WINDOWS\system32\VERSION.dll 0x76960000 - 0x76968000 <span> </span>C:\WINDOWS\system32\LINKINFO.dll 0x76970000 - 0x76996000 <span> </span>C:\WINDOWS\system32\ntshrui.dll 0x76b00000 - 0x76b11000 <span> </span>C:\WINDOWS\system32\ATL.DLL 0x75d70000 - 0x75e01000 <span> </span>C:\WINDOWS\system32\MLANG.dll 0x6d360000 - 0x6d36d000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\JdbcOdbc.dll 0x74610000 - 0x7464d000 <span> </span>C:\WINDOWS\system32\ODBC32.dll 0x76380000 - 0x763c8000 <span> </span>C:\WINDOWS\system32\comdlg32.dll 0x03a90000 - 0x03aa8000 <span> </span>C:\WINDOWS\system32\odbcint.dll 0x6dad0000 - 0x6daeb000 <span> </span>C:\WINDOWS\system32\odbccp32.dll 0x0dd70000 - 0x0ddaa000 <span> </span>C:\WINDOWS\system32\msjtes40.dll 0x0f9a0000 - 0x0f9ab000 <span> </span>C:\WINDOWS\system32\VBAJET32.DLL 0x0f9c0000 - 0x0fa22000 <span> </span>C:\WINDOWS\system32\expsrv.dll 0x6d790000 - 0x6d798000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\sunmscapi.dll 0x77a60000 - 0x77af6000 <span> </span>C:\WINDOWS\system32\CRYPT32.dll 0x77b00000 - 0x77b12000 <span> </span>C:\WINDOWS\system32\MSASN1.dll 0x4de10000 - 0x4de54000 <span> </span>C:\WINDOWS\system32\odbcjt32.dll 0x04710000 - 0x04880000 <span> </span>C:\WINDOWS\system32\msjet40.dll 0x04880000 - 0x04915000 <span> </span>C:\WINDOWS\system32\mswstr10.dll 0x5bfb0000 - 0x5bfbf000 <span> </span>C:\WINDOWS\system32\odbcji32.dll 0x03e20000 - 0x03e2d000 <span> </span>C:\WINDOWS\system32\msjter40.dll 0x03e40000 - 0x03e6c000 <span> </span>C:\WINDOWS\system32\MSJINT40.DLL 0x09770000 - 0x097bc000 <span> </span>C:\WINDOWS\system32\msrd3x40.dll VM Arguments: jvm_args: -Xms256m -Xmx256m java_command: ecm.legado.capex.swing.FImportadorPQ Launcher Type: SUN_STANDARD Environment Variables: PATH=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Arquivos de programas\MySQL\MySQL Server 5.0\bin;C:\Arquivos de programas\Autodesk\DWG TrueView\;C:\Arquivos de programas\Java\jre6\bin USERNAME=carinha // sim, eu mudei o log OS=Windows_NT PROCESSOR_IDENTIFIER=x86 Family 6 Model 15 Stepping 8, GenuineIntel --------------- S Y S T E M --------------- OS: Windows XP Build 2600 Service Pack 3 CPU:total 1 (2 cores per cpu, 1 threads per core) family 6 model 15 stepping 2, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3 Memory: 4k page, physical 261616k(41532k free), swap 631444k(110072k free) vm_info: Java HotSpot(TM) Client VM (11.0-b16) for windows-x86 JRE (1.6.0_11-b03), built on Nov 10 2008 02:15:12 by "java_re" with MS VC++ 7.1 time: Mon Jan 05 18:21:39 2009 elapsed time: 176 seconds
JDBC: Maldito Access: como resolver o problema “não é possível abrir mais tabelas (can’t open more tables)”
Então aconteceu com você: um belo dia teve de programar em Java acessando o maldito “banco de dados” Access… Seu código está escrito corretamente e a aplicação é iniciada. No início, tudo vai bem, você até se surpreeende com o fato de estar funcionando, até que, sem mais nem menos, começam a surgir excessões com as mensagens “Não é possível abrir mais tabelas” ou, em inglês: “can’t open more tables”.
É um daqueles momentos nos quais você realmente pensa em matar o infeliz que optou por usar este “banco de dados”. Mesmo consultas que só envolvam uma tabela começam a disparar esta excessão e, mesmo que você feche todas as suas instâncias das classes ResultSet e PreparedStatement, ou mesmo suas conexões com o banco, o erro persiste.
A impressão que temos é que só é possível trabalhar com este (argh) “banco de dados” se estivermos programando em VB ou VBA. Na prática, esta é a realidade, e, como irei mostrar a seguir, a solução para este problema não poderia ser mais tosca. Todo o problema está no driver de acesso ODBC ao Access.
Este driver, desenvolvido pela Microsoft (lógico) suporte apenas 1024 consultas a um banco Access. Sendo assim, você precisa fechar todas as consultas ou statements que venha a executar com relação a este banco. O mais interessante é: não basta chamar o método close() das classes ResultSet e PreparedStatment e, para minha surpresa, também não é necessário ficar criando e fechando sucessivas conexões com o “banco” Access.
Basta seguir o seguinte procedimento:
- Conecte-se ao “banco”. Você poderá reaproveitar sua conexão com o arquivo do Access. O problema não é com ela (bônus para você, pois não precisará mais sacrificar sua performance abrindo e fechando conexões a cada consulta).
- Instancie o seu objeto ResultSet ou PreparedStatement, e em seguida faça o que tem de fazer.
- Finalizada a execução, chame o método close da sua classe.
- Como se não bastasse chamar o método close(), defina a sua instância do objeto como null.
De tempos em tempos (vamos supor, de 20 em 20 execuções, por exemplo) chame o garbage colector do Java para limpar as variáveis não utilizadas. Pasme: somente assim as consultas são fechadas com o “banco e dados” em questão.
É uma gambiarra? Com certeza. A performance vai ser prejudicada? Pode apostar. É uma solução elegante? Nem um pouco. Mas por outro lado, você está usando uma das piores opções que existem. Só o fato de estar usando Access já é uma gambiarra, sendo assim, infelizmente, sofra as consequências.
Descobri esta solução enquanto desenvolvia uma “aplicação” que precisava do Access (no meu caso, o 97) no Netbeans. Ao executá-la no ambiente da IDE, o erro não aparecia. Ao executá-la independentemente, o erro aparecia (e sempre). Constatei então que o Netbeans chama o garbage colector constantemente, ao passo que minha aplicação não. Visto que já sabia do bug do driver, somei 2 + 2 e resolvi tentar esta solução. Para minha surpresa, funcionou melhor que o esperado. A perda de performance não foi tão grande e, para minha surpresa, a excessão simplesmente desapareceu.
Tudo bem: o principal problema com o Access foi resolvido. No entanto, faça um favor a você e aos futuros programadores que, por desventura venham a dar manutenção em seus sistemas: ESQUEÇA O ACCESS!

