Pergunta

Uma coisa que sempre foi uma dor é registrar erros de SQL (JDBC) quando você tem um PreparedStatement em vez da própria consulta.

Você sempre acaba com mensagens como:

2008-10-20 09:19:48,114 ERROR LoggingQueueConsumer-52 [Logger.error:168] Error 
executing SQL: [INSERT INTO private_rooms_bans (room_id, name, user_id, msisdn, 
nickname) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE room_id = ?, name = ?, 
user_id = ?, msisdn = ?, nickname = ?]

É claro que eu poderia escrever um método auxiliar para recuperar os valores e análise / substituir os pontos de interrogação com valores reais (e, provavelmente, ir por esse caminho, se eu não conseguir um resultado desta questão), mas eu só queria saber se o problema foi resolvido antes por outra pessoa e / ou se existe algum ajudante de registro genérico que faria isso automagicamente para mim.

Editado após algumas respostas:

As bibliotecas fornecidas até agora parece ser adequado para registrar as declarações de depuração, o que sem dúvida é útil. No entanto, eu estou olhando para uma maneira de tomar um PreparedStatement em si (não uma subclasse) e registrar sua instrução SQL sempre que ocorrer um erro. Eu não gostaria de implantar um aplicativo de produção com uma implementação alternativa de PreparedStatement.

Eu acho que o que eu estou procurando uma classe de utilitário, e não uma especialização PreparedStatement.

Obrigado!

Foi útil?

Solução

Eu tentei log4jdbc e fez o trabalho para mim.

SEGURANÇA NOTA: A partir de hoje Agosto de 2011, os resultados de um comando preparado log4jdbc logado não são seguros para executar. Eles podem ser usados ??para análise, mas nunca deve ser alimentado de volta para um SGBD.

Exemplo de registo gerado pelo logjdbc:

2010/08/12 16:30:56 jdbc.sqlonly org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate (DelegatingPreparedStatement.java:105) 8. INSERÇÃO EM a_Table (ID_FILE, code1, ID_G, ID_SEQUENCE, REF, NOME, BAR, DRINK_ID, uma quantidade, descrição, o estado, CODE2, REJECT_DESCR, ID_CUST_REJ) VALORES (2 '123', 1 '2', 'AA', 'temor', nulo, '0123', 4317,95, 'RCCC', '0', null, null, null)

A biblioteca é muito fácil de configurar:


A minha configuração com HSQLDB :

jdbc.url=jdbc:log4jdbc:hsqldb:mem:sample

Com do Oracle :

jdbc.url=jdbc:log4jdbc:oracle:thin:@mybdd:1521:smt
jdbc.driverClass=net.sf.log4jdbc.DriverSpy

logback.xml:

<logger name="jdbc.sqlonly" level="DEBUG"/>

Pena que não estava em um repositório maven, mas ainda útil.
Pelo que eu tentei, se você definir

Você só vai conseguir as declarações em erro, no entanto, eu não sei se esta biblioteca tem um impacto sobre o desempenho.

Outras dicas

Isto é muito dependente do banco de dados. Por exemplo, eu entendo que alguns drivers JDBC (por exemplo, Sybase, talvez MS-SQL) punho preparado declarações de criar um procedimento armazenado temporário no servidor, e em seguida, invocando esse procedimento com os argumentos fornecidos. Assim, o SQL completa nunca é realmente passado do cliente.

Como resultado, o JDBC API não expõe a informação que você está depois. Você pode ser capaz de lançar sua declaração de objetos a implementação do controlador interno, mas provavelmente não -. Seu appserver pode muito bem envolver as declarações em sua própria implementação

Eu acho que você pode apenas ter que morder a bala e escrever sua própria classe que interpola os argumentos para o SQL espaço reservado. Isso vai ser difícil, porque você não pode pedir PreparedStatement para os parâmetros que foram estabelecidos, de forma que você tem que lembrar-los em um objeto auxiliar, antes de passá-los para a declaração.

Parece-me que uma das bibliotecas de utilitários que envolvem a execução de motorista objetos é a maneira mais prática de fazer o que você está tentando alcançar, mas isso vai ser desagradável de qualquer maneira.

Use P6Spy : Sua Oracle, MySQL, JNDI, JMX, Spring e Maven amigável. Altamente configurável. integração de nível simples e de baixo Pode imprimir o stacktrace . Só é possível imprimir chamadas pesadas -. tempo threashold base

  1. Se você estiver usando MySQL, o MySQL Connector PreparedStatement.toString () faz incluem os parâmetros ligados . Apesar de terceiros pools de conexão pode quebrar isso.

  2. Sub-classe PreparedStatement para construir a string de consulta como parâmetros são adicionados. Não há nenhuma maneira de extrair o SQL de um PreparedStatement, como ele usa um formato binário compilado.

LoggedPreparedStatement parece promissor, embora eu não tentei.

Uma das vantagens destes sobre um motorista de proxy que registra todas as consultas é que você pode modificar a string de consulta antes de registrá-lo. Por exemplo, em um ambiente PCI você pode querer mascarar números de cartão.

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