[RESOLVIDO] Usando o mesmo PreparedStatement

15 respostas
I

Olá. Eu estou tendo um problema com o uso de PreparedStatement. Gostaria de saber se tem como eu usar o mesmo prepared statement.

Olha, eu tenho que passar um Select e as vezes vai ter uns parâmetros diferentes.

public Vector pesquisarPeca(String busca, String campo, int index)
    {
        StringBuilder sql = new StringBuilder();
        Vector itens = new Vector();       

        try
        {
            sql.append("SELECT codigo, descricao FROM peca WHERE ");
            sql.append(campo);
            sql.append(" LIKE '");
            sql.append(busca);
            sql.append("%'");

            PreparedStatement stmPp = con.prepareStatement(sql.toString());

            ResultSet rs = stmPp.executeQuery();

            while(rs.next())
            {
                itens.add(rs.getString(index));
            }            

            rs.close();
            stmPp.close();

            this.con.close();
            
            return itens;

        } catch (SQLException ex)
        {
            JOptionPane.showMessageDialog(null, ex);
            return null;
        }
    }

Eu sei, eu estou fechando ele. Mas não tem como reabir? Pq eu vi que pode ser um problema deixa-lo aberto. Alguma ideia?

15 Respostas

E

Para reusar um mesmo PreparedStatement, apenas os valores (não os nomes dos campos, por exemplo) podem ser alterados.

I

Quer dizer que tenho que fazer outro prepared statement? Você conhece uma forma mais pratica de fazer isso? Pois o ideal seria eu passar por parâmetro mesmo o campo que quero.

C

Alerta de possível SQL injection em seu código, tenha certeza de usar os métodos setString() da classe PreparedStatement para substituir os valores dinâmicos de sua sql.
Caso você precise executar duas queries, use o mesmo identificador (no seu caso stmPp) para receber um novo objeto gerado pelo método prepareStatement();

PreparedStatement stmPp = null;
stmPp = con.prepareStatement("sql1");
//executa
stmPp = con.prepareStatement("sql2");
//executa
I
sql.append("SELECT codigo, descricao FROM peca WHERE '?' LIKE '?%'");            

            PreparedStatement stmPp = con.prepareStatement(sql.toString());
            
            stmPp.setString(1, campo);
            stmPp.setString(2, busca);
            
            ResultSet rs = stmPp.executeQuery();

No caso isso evita SQL Injection não é?

Mas eu não entendi o esquema das duas querries. Quando eu chamar o metodo de pesquisa, como ele vai saber qual usar? E também talvez eu precise executar mais de duas querries.

Preciso chamar assim
DefaultComboBoxModel itensCod = new DefaultComboBoxModel(c.pesquisarPeca(str, "codigo", 1));
                       DefaultComboBoxModel itensDesc = new DefaultComboBoxModel(c.pesquisarPeca(str, "codigo", 2));
C

Desculpa amigo, mas pra mim não ficou muito claro o que você quer fazer. Tem como explicar objetivamente o que você está querendo fazer?

F
Iskifi:
Olá. Eu estou tendo um problema com o uso de PreparedStatement. Gostaria de saber se tem como eu usar o mesmo prepared statement.

Olha, eu tenho que passar um Select e as vezes vai ter uns parâmetros diferentes.

public Vector pesquisarPeca(String busca, String campo, int index)
    {
        StringBuilder sql = new StringBuilder();
        Vector itens = new Vector();       

        try
        {
            sql.append("SELECT codigo, descricao FROM peca WHERE ");
            sql.append(campo);
            sql.append(" LIKE '");
            sql.append(busca);
            sql.append("%'");

            PreparedStatement stmPp = con.prepareStatement(sql.toString());

            ResultSet rs = stmPp.executeQuery();

            while(rs.next())
            {
                itens.add(rs.getString(index));
            }            

            rs.close();
            stmPp.close();

            this.con.close();
            
            return itens;

        } catch (SQLException ex)
        {
            JOptionPane.showMessageDialog(null, ex);
            return null;
        }
    }

Eu sei, eu estou fechando ele. Mas não tem como reabir? Pq eu vi que pode ser um problema deixa-lo aberto. Alguma ideia?


Vc pode reusa-la na mesma conexão...ou seja na mesma chamada...para deixa-lo aberto vc tera que segurar a conexão para o banco de dados que não é um boa pratica para aplicações web. Caso seje desktop, dai vc pode deixar...

I

Olhe ali, eu preciso retornar a minha pesquisa em um defaultcomboboxmodel.

Ai eu tenho o método de pesquisa com diversos parâmetros.

Parameter index out of range (1> number of parameters, which is 0).

É o erro de sql que da.

I

Bom, então o certo seria eu usar uma conexão diferente apenas pra esse método de pesquisa? Sim, é uma aplicação de desktop.

M
Iskifi:
sql.append("SELECT codigo, descricao FROM peca WHERE '?' LIKE '?%'");            

            PreparedStatement stmPp = con.prepareStatement(sql.toString());
            
            stmPp.setString(1, campo);
            stmPp.setString(2, busca);
            
            ResultSet rs = stmPp.executeQuery();

No caso isso evita SQL Injection não é?
...[/code]

Só uma dúvida boba. Por que isso evita sql injection?
Por exemplo, se a variável "campo" tiver esse conteúdo "x' AND CAMPO=1 --" esse valor seria substituído na sql lá em cima, não?

F

Aplicações desktop, abrem apenas 1 conexões que é compartilhada em todas as GUI. Por isso, vc pode usar a estratégia de “cache” para todos os seu preparatedStatements numa boa…

V

Esse “design pattern” geralmente é visto em aplicações de faculdade, mas não deveria estar em aplicações desktop sérias.

  1. Múltiplas threads não deveriam compartilhar a mesma conexão;
  2. A conexão tem tempo de vida do lado do servidor;
  3. Conexões consomem recursos do banco de dados. Se o usuário estiver com a aplicação parada, essa conexão deveria estar fechada.
  4. É uma boa usar um Pool de conexões, exatamente igual você faria numa aplicação web (mas talvez, configurado para um número bem menor de conexões simultâneas: geralmente entre 2 ou 3). E isso é tão fácil de fazer que não vejo uma justificativa cabível para não fazê-lo.
F

Múltiplas threads de leitura podem sim…transacionais não.

Questionável: Dependente do tipo do driver e do tipo de uso que a aplicação o faz…

Questionável:

  • Aplicações fat cliente tem recursos para suportar isso…diferentes de aplicações web…mas não é o caso.
  • Controle de sessão normalmente são feitos por critérios de segurança.
  • É claro que pode ser fechado e reaberto quando o usuário voltar a usar…
  • Unica justificativa para isso é quando a aplicação fat tiver multiplas thread transacionais simultâneas que são casos bem raros, caso contrario não existe arquiteturalmente requisitos que cubram isso.

Cada caso é um caso e assim não podemos replicar experiencias de 1 para outros…
Mas resumidamente é uma conexão por aplicação desktop, é claro que pode existir casos que não seje suficiente…mas sem requisitos reais não tem como justificar…

V

O problema é que a camada de conexão dificilmente saberá que tipo de threads irão rodar sobre ela. E, se você está projetando o seu sistema para que mais de um programador dê manutenção, também é perigoso para você assumir esse tipo de coisa.

2. A conexão tem tempo de vida do lado do servidor;
Questionável: Dependente do tipo do driver e do tipo de uso que a aplicação o faz…

Isso jamais foi questionável. É uma premissa de qualquer servidor, por mais simples que seja. O tempo pode ser longo, mas ele sempre existe. Você deve no mínimo se prevenir para caso seu usuário deixe a máquina ligada numa manhã e resolva usar a aplicação no dia seguinte, ou para caso ele coloque o computador em stand by.

3. Conexões consomem recursos do banco de dados. Se o usuário estiver com a aplicação parada, essa conexão deveria estar fechada.
Questionável:

  • Aplicações fat cliente tem recursos para suportar isso…diferentes de aplicações web…mas não é o caso.

Também não tem nada questionável. Os “recursos” que fat clientes tem para suportar isso são justamente um controle melhor da conexão, que o pool de conexões que recomendei faz. Caches e outros recursos apenas evitam que a conexão seja usada, mas não impede que ela se mantenha presa, se você não a fechar.

  • Controle de sessão normalmente são feitos por critérios de segurança.
  • É claro que pode ser fechado e reaberto quando o usuário voltar a usar…
  • Unica justificativa para isso é quando a aplicação fat tiver multiplas thread transacionais simultâneas que são casos bem raros, caso contrario não existe arquiteturalmente requisitos que cubram isso.

Eu discordo. Abrir multiplas conexões para multiplas threads, é um único recurso do pool. Os outros dois itens que você citou também são controlados pela maioria dos pools de conexão. Eles também testar se a conexão está saudável e reciclam caso seja necessário. Caso não haja conexões disponíveis ele faz com que threads esperem, de maneira segura.

Enfim, não quis criticar exatamente o que você falou, mas a forma. Uma conexão sozinha não é o design pattern de um singleton que mantém uma conexão aberta para sempre (era isso que eu queria frizar). Esse sim, é um design pattern irresponsável. É muito melhor usar aplicações já existentes, como os pools, que controlam a abertura e o fechamento dessa conexão, e trabalhar com a filosofia de que, para a aplicação, a conexão está sempre fechada e não aberta. Mesmo que o pool gerencie uma conexão só.

Mas realmente, me enganei ao dizer que o número de conexões de uma aplicação desktop não é baixo, e certamente ele tende a uma só. Só quero deixar claro que não se pode confundir com o tal Singleton.

F

Então ViniGodoy
Discutir opções arquiteturais sem requisitos e cenário tudo pode ser possível e tudo pode ser viável kkkk
Uma aplicação fat pode fazer uso de singleton sim ou de pool…tudo depende do cenário.

I

Ok… a conversa de vocês deu algumas coisas pra eu estudar hehe

Em fim, eu consegui solucionar o problema por deixar a conexão sempre aberta. Em uma aplicação desktop, pelo que vi isso não é o problema. Quando o usuário finaliza a aplicação eu fecho a conexão.

Então, algum problema com isso, ou é valido pra essa aplicação?

Criado 25 de julho de 2011
Ultima resposta 26 de jul. de 2011
Respostas 15
Participantes 6