Pergunta

PreparedStatement ps = con.createStatement("select * from table1 where last_name like ?");
ps.setString(1, "'%"+lastName+"'");

Será que este trabalho o mesmo que ...

Statement s = con.createStatement("select * from table1 where last_name like %"+ lastName);

Ou PreparedStatement retirar o sinal%?

Foi útil?

Solução

% é um carácter universal (no Oracle pelo menos), por isso, em teoria, ambos devem funcionar da mesma (supondo que você adicione a falta aspas simples)

No entanto, o primeiro seria considerado como melhor prática, uma vez que pode permitir que o optimser banco de dados não para re-analisar a instrução. O primeiro deve também protegê-lo contra injeção de SQL enquanto o segundo pode não ser.

Outras dicas

O segundo não vai funcionar porque você esqueceu as aspas em torno da corda! ao lado que você precisa escapar e ter cuidado para injecção SQL.

Suponha SQL

lastName = "and a quote' or a bracket()";
Statement s = con.createStatement("select * from table1 where last_name like '%"+ lastName + "'");

o SQL resultante é:

select * from table1 where last_name like '%and a quote' or a bracket()'

que irá falhar

variáveis ??de ligação torná-lo sempre mais seguro para trabalhar.

A resposta curta é: Sim, supondo que você corrigir o citando, os dois devem dar os mesmos resultados. O sinal de porcentagem não será "retirados" de uma declaração preparada, mais do que qualquer outro personagem seria.

resposta mais longa: A questão da declaração preparada vs declaração de uso único pode ser complexa. Se você está indo só para executá-lo uma vez, a declaração preparada levará mais tempo, porque o motor de banco de dados tem que fazer toda a configuração para uma declaração preparada, em seguida, insira os valores, em seguida, tê-lo flutuando em um cache até que o motor decide nivelá-lo. Além disso, o otimizador muitas vezes não pode processar uma declaração preparada de forma tão eficiente. O ponto inteiro de uma declaração preparada é que o otimizador analisa a consulta e inventa um plano de consulta uma vez. Suponha que você dizer algo como "select nome_cliente do cliente, onde CUSTOMER_TYPE =? E customer_zip =?". Você tem índices em ambos os tipos e zip. Com uma declaração de uso único (com valores reais preenchidos em vez de pontos de interrogação, é claro), o otimizador de consulta em muitos motores de banco de dados podem olhar para as estatísticas sobre a distribuição de valores para os dois campos, e escolher o índice que vai dar o menor conjunto de registos, em seguida, ler todos estes sequencialmente e eliminar os registos que falham o segundo teste. Com uma declaração preparada, deve escolher o índice antes de saber quais os valores serão fornecidas, por isso pode escolher o índice menos eficiente.

Você deve nunca, nunca na dor da morte código já gravação que apenas tapas aspas em torno de um valor desconhecido e enchê-lo em uma instrução SQL. De qualquer uso preparado declarações, ou escrever uma função que escapa corretamente qualquer cotações incorporadas. função Tal é trivial para escrever. Eu não entendo por que JDBC não incluir um, então você tem que escrevê-lo sozinho e incluí-lo com cada aplicativo. (Isto é especialmente verdade, dado que alguns dialetos SQL têm diferentes aspas simples que devem ser escapou caracteres.)

Aqui está um exemplo de uma função em Java:

public static String q(String s)
{
  if (s==null)
    return "null";
  if (s.indexOf('\'')<0)
    return "'"+s+"'";
  int sl=s.length();
  char[] c2=new char[sl*2+2];
  c2[0]='\''; 
  int p2=1;
  for (int p=0;p<sl;++p)
  {
    char c=s.charAt(p);
    if (c=='\'')
      c2[p2++]=c;
    c2[p2++]=c;
  }
  c2[p2++]='\'';
  return new String(c2,0,p2);
}

(Nota:. I acabou de editar essa função a partir da versão que eu puxado para fora do meu código para eliminar alguns casos especiais que não são relevantes aqui - desculpe se eu introduzi alguns erros ao fazer isso)

Eu costumo dar-lhe um nome muito curto, como "q" para que eu possa escrever apenas:

String sql="select customer_name from customer where customer_type="+q(custType)
  +" and customer_zip="+q(custZip);

ou rápido algo e fácil assim. É uma violação das "funções give completos e nomes significativos", mas acho que vale a pena aqui, onde eu possa usar os mesmos tempos de função de dez em um comunicado.

Então eu sobrecarregá-lo a tomar datas e números e outros tipos especiais e tratá-los adequadamente.

Usando declarações preparadas com variáveis ??de ligação é muito mais rápido, porque isso significa que a Oracle não tem de analisar (compilação) instruções SQL novamente e novamente. Oracle armazena todos os comandos executados em conjunto com os planos de execução em uma tabela hash compartilhada para reutilização. No entanto a Oracle só irá reutilizar o plano de execução de instruções preparadas com variáveis ??de ligação. Quando você faz:

"SELECT * FROM table1 onde last_name como%" + lastName

A Oracle não reutilizar o plano de execução.

(Oracle hashes cada instrução SQL e quando você usa SELECT ... WHERE last_name como% "+ lastName cada instrução SQL tem um valor de hash diferente porque sobrenome variável quase sempre tem um valor diferente, por isso, a Oracle não pode encontrar o sql declaração na tabela hash e Oracle não pode reutilizar o plano de execução.)

Em uma situação de multi concorrência, o impacto é ainda maior porque a Oracle bloqueia esta tabela hash compartilhada. Esses bloqueios não duram muito tempo, mas em um multi concorrência bloqueio situação realmente começa a doer. Quando você usa instruções preparadas com variáveis ??de ligação quase nenhum bloqueio é necessário. A Oracle pela forma como chama as de spin fechaduras travas.

Somente quando você tem uma casa dataware e suas consultas demorar alguns minutos (relatórios) em vez de frações de segundos você pode usar declarações não-preparados.

Muitas vezes usamos a primeira abordagem sem problema. Por exemplo:

String sql = "SELECT * FROM LETTER_BIN WHERE LTR_XML Like ' (?) ' AND LTR_BIN_BARCODE_ID = (?)";
try
{
    // Cast a prepared statement into an OralcePreparedStatement
    opstmt = (OraclePreparedStatement) conn.prepareStatement(sql);
    // Set the clob using a string
    opstmt.setString(1,fX.toString());
    // for this barcode
    opstmt.setLong(2,lbbi);
    // Execute the OraclePreparedStatement
    opstmt.execute();
} catch(java.sql.SQLException e)
{
    System.err.println(e.toString());
} finally
{
    if(opstmt != null)
    {
        try
        {
            opstmt.close();
        } catch(java.sql.SQLException ignore)
        {
            System.err.println("PREPARED STMT ERROR: "+ignore.toString());
        }
    }

}

Ok, eu vou levar a sua palavra para ela em Oracle. Isto é, não surpreendentemente, banco de dados do motor dependentes. Postgres comporta-se como I descritos. Ao usar o MySQL a partir JDBC - pelo menos a partir de um par de anos atrás, quando eu última olhei para isso - não há praticamente nula diferença entre declarações preparadas e declarações de uso único, porque o driver MySQL JDBC salva declarações preparadas no cliente lado, quando você executar a declaração preparada ele preenche os valores como texto e navios-o para o motor de banco de dados. Assim, tanto quanto o motor está em causa, não há realmente nenhuma coisa como uma declaração preparada. Eu não seria de todo surpreso ao saber que outros motores têm um comportamento completamente diferente.

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