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

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.

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

stmt.setNull(1, Types.VARCHAR);

Qual execeção é disparada?

Eu recupero a exceção assim:

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

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

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?

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

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.

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:

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

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.

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…

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

Valeu.