Inserir NULL no banco através do PreparedStatement [RESOLVIDO]

10 respostas
V

Olá pessoal, estou com a seguinte questão, eu tenho o seguinte código:

String SQL = "INSERT INTO alerts.analyzer VALUES (?,?,?,?,?)";
PreparedStatement st = db.prepareStatement(SQL);
st.setInt(1,analyzerId);
st.setString(2,name);
st.setString(3,manufacturer);
st.setString(4,model);
st.setString(5,version);
linhas = st.executeUpdate();

Na tabela ‘analyzer’ do banco o único campo obrigatório é a chave primária: ‘analyzerId’, todos os outros campos podem ser NULL. Os valores para os atributos eu consigo através de um formulário web (todos os atributos são inicializados com null, se o formulário não passar nenhum valor ele continua valendo null).

Se no formulário eu quiser deixar o campo ‘name’ sem preencher para que seja inserido NULL ao banco eu consigo uma exceção, porque o método ‘setString’ foi feito para Strings e não para valores NULL, como eu posso resolver isso ?
Daria pra fazer um IF pra cada campo verificando se o valor é null antes de inserir ao banco, se for null é usar o setNull ao invés do setString, mas é inviavel fazer um if para cada campo em minha opinião. Existe alguma forma melhor e mais usual de resolver esse problema ?

Obrigado.

10 Respostas

B

Não me lembro de precisar disso, mas sei desse código.

stmt.setNull(1, Types.VARCHAR);

Qual execeção é disparada?

V

Eu recupero a exceção assim:

catch (Exception ex)
{
System.out.println("ERRO: "+ex.getMessage());
}

A unica coisa que sai é: “ERRO: null”

B

Manda o stacktrace. Não tenho como testar agora, e realmente não lembro de ocorrer isso

} catch(Exception ex) {
   ex.printStackTrace();
}

O setNull funcionou?

V

Olá, segue StackTrace:

java.lang.NullPointerException
	at eClasses.Analyzer.saveDb(Analyzer.java:111)
	at org.apache.jsp.addAnalyzer_jsp._jspService(addAnalyzer_jsp.java:82)
	at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
	at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:722)

O setNull funcionou sim, e uma coisa engraçada é que o setString também funcionou, agora só estou com problema com o setInt ;s

B

Para o setInt é a mesma coisa.

stmt.setNull(1, Types.INTEGER);

Fiz um teste aqui com HSQLDB e String pode user o setString(1, null) mas com o int tem que ser o setNull(1, Types.INTEGER)

Não lembrava de precisar fazer isso. Mas se está vindo null no request é porque os dados não estão vindo. Campos desabilitados ou os campos realmente não existem.

Talvez seja o comportamento normal da sua aplicação.

V

Olá estou usando o JDBC para o banco Postgresql.

De fato fiz uns testes e o setNull também funcionou para inteiros, o problema é que não é todas as vezes que eu quero inserir o null no campo, com o setNull ele sempre irá inserir o null.

Suponha que eu tenho o atributo Int ‘processId’, algumas vezes ele será null e outras vezes não, e eu queria usar um mesmo método para inserir este atributo ao banco sendo ele null ou não.

Da forma que está eu teria que usar dois métodos, o setInt para quando ele fosse de fato um número e o setNull para caso ele fosse null. Como eu tenho muitas entidades com muitos atributos que se encaixam com o exemplo dado a quantidade de código a mais que eu precisaria colocar, para fazer a verificação se o atributo é null antes de inserir ao banco, seria bem grande, a intenção era encontrar uma forma alternativa para isso.

Eu olhei o cabeçalho da função setInt e notei isso: setInt(int parameterIndex, int x)

Ela recebe um inteiro do tipo primitivo int e não um inteiro do tipo abstrato Integer, ai está o motivo do setInt não conseguir trabalhar com o null assim como o setString consegue, já que String é classe e não tipo primitivo.

Enfim acho que para conseguir o que eu queria eu precisaria de uma classe: setInteger(int parameterIndex, Integer x) ;s

Espero que eu tenha conseguido explicar :slight_smile:

V

Será que eu conseguiria criar essa classe setInteger(int parameterIndex, Integer x) a partir da classe setInt, somente mudando o tipo int para Integer ?

B

Entendi sua explicação e seu entendimento está correto.

É que realmente faz tempo que não me preocupo com o null em int.

Bom, você vai ter tomar uma decisão se realmente precisa setar null no campo.

if (var == null)
    stmt.setNull(1, Types.INTEGER);
else
    stmt.setInt(1, var);

Se puder setar 0 na coluna, poderia ser assim:

stmt.setInt(1, var == null ? 0 : var);

Apenas mantém o código menor.

B

Pra fazer isso, você precisaria extender a classe PreparedStatement do driver pra no final fazer o if.

Já que o dado gravado no banco é o 0 e não o java.lang.Integer.

No final haverá um if em algum lugar…

V

Entendi Bruno, muito obrigado por sua prestação, foi muito útil, vou acabar tendo que me render ao if mesmo HAHA.

Valeu.

Criado 13 de março de 2013
Ultima resposta 14 de mar. de 2013
Respostas 10
Participantes 2