Retirando o SQL do seu código Java

30 respostas
A

Assunto: Aprenda a usar o PreparedStatement para retirar todo código SQL do seu código java, e separá-lo em um arquivo de configuração. Além de uma boa prática, você não precisará mais recompilar o seu código quando necessário mudar pouca coisa de uma SQL.

Você pode ler este artigo na íntegra http://www.guj.com.br/java.artigo.115.1.guj

Por favor, coloque os seus comentários sobre este artigo aqui.

30 Respostas

R

Uma dica se alguem for quer usar LIKE: faca o sql

SELECT campoX FROM tabela WHERE outroCampo LIKE ?

e para atribuir o valor faca

....
pstmt.setString(1, "%valor%")

ou seja, passe as “%” pelo setXXX ao inves de colocar direto no sql

[]'s
Rafael Steil

D

Me parece legal a solução de se tirar o SQL do código, porém seria uma solução um pouco pesada, digo, pode causar overhead no processamento e acesso ao arquivo de configuração das queries.

Uma solução seria carregar as queries em um Properties e acessar da memória, o que pode causar muito uso de memória ainda. E mesmo assim teria de haver um sistema de atualização das queries, caso fossem alteradas nos arquivos de configuração.

P

“danieldestro”:

Uma solução seria carregar as queries em um Properties e acessar da memória, o que pode causar muito uso de memória ainda. E mesmo assim teria de haver um sistema de atualização das queries, caso fossem alteradas nos arquivos de configuração.

isso ja acontece, por isso tem o singleton la! pra ler soh uma vez.

quanto a reler o arquivo, depende do seu uso. no meu caso e maioria dos casos ninguem fica mudando sql em tempo de execucao!

F

Estou construindo uma aplicação para acessar o Sybase IQ, front end de uma grande aplicação com tabelas de mais de 100 millhoes de registros estou seguindo uma orientação da Sun para utilizar EJB Entity BMP. Então são várias consultas parametrizadas, neste caso eu achei interessante essa idéia e gostaria de unir a duas, mas tenho uma duvida, pois tenho que montar a query dinamicamente, de acordo com os parâmetros passados, tem aplicação que posso ter até 20 parâmentros diferentes sem alguem tiver alguma idéia…

Outra pergunta se eu usar o PreparedStatement

Ex.: select campo from tabela where campo1= ? and campo2= ? and …

Sou obrigado a passar todos os parâmetros?? E se eu passar apenas o primeiro parametro a query ficaria de que forma?

D

Paulo, mas uma vez parabens pela excelente materia, eu programo já algum tempo em java e nunca havia tentado fazer isto ( isolar querys ), fica muito bom para manutencao e melhor ainda para portar para outras bases de dados, olhe que demo interessante eu fiz usando esta tecnica mais um pouco de minha experiencia juntando FLASH+SERVLET+SQL.
www.paxdrogaria.hpg.com.br
um abraco.

P

Olá Daniel. Fico contente com seus elogios e isso incentiva a mim e todos os outros do GUJ.

A pagina aqui abriu soh uma vez, e travou. Dei reload e ele está tentando conectar na porta 1000 de um IP (o seu ip?), mas sem sucesso.

Alias, se voce quiser escrever um artigo sobre o Flash acessando http, no caso uma servlet e tal, seria MUITO legal para todos!

D

Oi Paulo, desculpe eh porque esta pagina eh um modulo que faz parte de um projeto maior , eu ainda estou fazendo algumas alteracoes só esta no ar de vez enquando para teste se quiser eh so me avizar a hora que vc quizer ver e eu deixo ela carregada, pode mandar um email [email removido] ou ligar [telefone removido] e eu deixo ok.

D

Não quero ser rude, mas todo mundo que deseja desenvolver em Java precisa saber o que é um singleton. Li sobre o assunto e me parece que, na verdade, existem inúmeras situações em que singletons deixam de atuar como singletons (onde se pode criar mais de uma instância da classe – que deveria ser um singleton). É um assunto bastante extenso e bem interessante.

Estou estudando Java há mais de um ano e gostaria de saber por que o autor diz que, uma classe que contém apenas métodos estáticos ocasiona o que ele chamou de “perda da OO”? Fico confuso por que a classe java.lang.Math contém apenas métodos e campos estáticos.

Sobre o artigo, é excelente![/code]

P

Creio que não haja a necessidade de alguem saber o que é o singleton, quando se começa a programar em java. Mais para a frente pode ficar essencial, assim como multiton e factories.

Quando você tem uma classe só com métodos estáticos você perde OO, é por causa do seguinte:

Você não pode instaciar essas classes porque normalmente o construtor delas é privado. Você não pode usar polimorfismo com elas porque, ou você não tem como criar instâncias delas, ou elas derivam diretamente de Object e são final. Com isso, você já não mexe mais com objetos, mas sim com procedimentos: taí a conclusão, a programação vira procedural!!!

Dois casos clássicos são a java.lang.System e Math. Só tem atributos e métodos estáticos, com isso, você nunca poderá passar uma instância da Math como parâmetro. Faz de conta que existe a matemática normal e a booleana, e você quer decidir qual usar em runtime, com este “approach”, de apenas métodos estáticos, você teria de usar reflection para mudar a classe escolhida: péssima escolha.

Existem casos que é legal você definir a classe a ser usada como argumento, mas na maior parte dos casos é interessante você mandar uma instância.

Creio que eu embaralhei você mais ainda, vou escrever algo sobre Singleton logo logo…

D

Não, ok!
Eu imagino apenas que, dependendo do problema que se deseja resolver, seja prático você criar um ou mais métodos (que sejam extremamente necessários, mas que não se enquadram em nenhum outro contexto) como métodos estáticos dentro de uma classe que não tenha um construtor explicitamente declarado.

Só para reforçar a idéia, – e quem trabalha com desenvolvimento de software em empresas que não são do ramo (como um atacadista ou uma indústria de beneficiamento por exemplo) sabe do que eu estou falando – muitas vezes os desenvolvedores são exortados a resolver um problema extremamente difícil que envolva cálculos complexos (já aconteceu comigo) em um tempo extremamente curto; daí você desenvolve uma ou mais classes para resolver o problema e 2 ou 3 métodos de cálculo simplesmente não se enquadram no contexto das demais classes criadas (ou das existentes)…; eu implementaria esses métodos numa classe separada como métodos estáticos – todos em um pacote específico para a solução do problema.

Acho que, se a solução for bem projetada e as premissas de acesso à dados da OO não forem quebradas, não há mal algum em usar todas as possibilidades da linguagem – como a Sun fez com o java.lang.Math.

(Ah, valeu pela resposta a jato!)

Abraços. :slight_smile:

A

Perguntinha de iniciante, como esta o conteudo do arquivo querymysql.txt,
e como a classe sabe como encontrar as consultas.
por acaso esta assim:

ADICIONA_FULANO = INSERT * FROM tbfulano (?,?,?,?)

desculpe a perguntinha besta …
:oops:

P

fica desse jeito mesmo!

para ela ler deste arquivo, utilize um objeto da classe java.util.Properties

A

Da pra dar so uma canja de como eu uso essa classe …

Obrigado pela resposta !!!

:lol:

E

// Read properties file. Properties properties = new Properties(); try { properties.load(new FileInputStream("filename.properties")); String string = properties.getProperty("a.b"); } catch (IOException e) { }

R

Pessoal:

Não sei se tem muito a ver com este topico, mas uma boa dica, e acho que é o que todos fazem, eh separar os códigos SQL da interface. Aqui em minha empresa usamos camadas para separar o codigo que acessa o BD da interface em si. Acho isso algo muito util, pois podemos utilizar a tecnica de reutilização de código

Ate mais…

A

Valew

:smiley:

B

Apliquei esta solução aos meus servlets, mas tem um problema… quando faço:

proprities.load(new FileInputStream(file));

Ele por defeito vai procurar o ficheiro a C:\Tomcat\bin

Eu sei que posso fazer:

File fil = new File("D:\JavaProjects\MyProject\" + file);
proprities.load(new FileInputStream(fil));

Assim já posso dar um caminho e vai funcionar… mas é mau pq se um dia mudar de directorio tenho q mudar o codigo… a minha questao é como faço para ir directamente ao directorio onde estao os meus servlets ?

R

Essa eh facil: utilize o metodo getRealPath() da classe ServletContext. Uma maneira facil e corretamente correta seria assim:

...
private String pathDaAplicacao;
...
public void init(ServletConfig config)
{
    super.init(config);

    pathDaAplicacao = config.getServletContext().getRealPath("")
}
..

E entao “pathDaAplicacao” contera o caminho completo ate a raiz do teu webapp.

Rafael

B

O problema é que a class que cria o objecto para buscar as expressoes SQL não é uma servlet… e o seu construtor é private, nao podendo assim passar parametros de outras servlets… veja:

public class SQLManager {
	protected Properties sqlStatements;
	protected static SQLManager sqlManager = new SQLManager("SQLStatements.sql");
	
	private SQLManager(String file) {
		sqlStatements = new Properties();
		try {
			sqlStatements.load(new FileInputStream(file));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static SQLManager getSQLManager() {
		return sqlManager;
	}
}

Como posso especificar o caminho para a raiz da minha webapp neste caso?

R

Voce pode entao implementar um metodo init() e passar os parametros:

public class SQLManager {
	protected Properties sqlStatements;
	protected static SQLManager sqlManager;
   
	private SQLManager(String file) {
		sqlStatements = new Properties();
		try {
			sqlStatements.load(new FileInputStream(file));
		} 
		catch (FileNotFoundException e) {
			e.printStackTrace();
		} 
		catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static SQLManager getSQLManager() {
		return sqlManager;
	}
	
	public static void init(String baseDir) {
		 sqlManager = new SQLManager(baseDir + "SQLStatements.sql");
	}
}

Entao voce chama init(“xxxx”) para iniciar o Singleton e entao o resto funciona normalmente, com voce chamando getSQLManager() para pegar a instancia.

Rafael

R

Na empresa onde trabalho, o sistema que fizemos em java utiliza esse conceito de tirar o SQL do codigo…com certeza, hj, se eu for fazer, por exemplo uma interface swing com SQL no meio fico perdido… :smiley:

Acho interessante trabalhar com o conceito multicamadas, pois ajuda a estruturar o código, além de facilitar futuras manutenções!!

Ate mais…

B

Pessoas, em java só é possível criar uma consulta dinamicamente usando ‘?’, não existe algo como deelphi em que vc dá nome aos campos??

té,

R

bandrade:

Não sei se é isso que queria saber, mas podemos criar métodos get se set para atualizar variaveis que fazem o contato com o BD, assim:

private int codigo;

public int getCodigo()
{
     return codigo;
}

public void setCodigo(int pCodigo)
{
      pCodigo = Codigo;
}

Dai, quando vc vai fazer a “conversação” com o banco de dados, ou, quando vc quer recuperar na interface os valores ou ate mesmo, no caso do set, setar valores no BD, ao qual é manipulado em outra classe, vc pode usar um método set para setar as informações e o método get para “pegar” do BD.

Bom, acho que é mais ou menos por ai…

espero ter ajudado…

ate mais…

P

“bandrade”:
Pessoas, em java só é possível criar uma consulta dinamicamente usando ‘?’, não existe algo como deelphi em que vc dá nome aos campos??

té,

acho que o que esta perguntando eh se os prepared statements podem indexar as variaveis por nome, em vez de indices da posicao dos “?”, nao?

a resposta eh nao :frowning: Um preparedStatement como esse seria muito legal. muitas pessoas escrevem o proprio, ja que essa ideia eh melhor que setObject(1, x)

B

é mais ou menos isso mesmo, no delhpi vc monta a sql +/- assim

vc tem a quer la com o seguinte sql:
select * from remedios where lote = :lote_id

aí o usuário informa qual o loet ele quer
query1.sql.Fieldbyname(‘lote_id’).Value := 9;

e vc executa a sql
query1.open

com java fica muito ruim só com os inices dos ? pq pode rolar confunsão…

E

Testei a sua solução e funcionou bacana! Parabéns! Mas… eu tenho uma aplicação que não é WEB! Como faço pra resolver o problema do caminho do arquivo???

“Rafael Steil”:
Voce pode entao implementar um metodo init() e passar os parametros:

public class SQLManager {
	protected Properties sqlStatements;
	protected static SQLManager sqlManager;
   
	private SQLManager(String file) {
		sqlStatements = new Properties();
		try {
			sqlStatements.load(new FileInputStream(file));
		} 
		catch (FileNotFoundException e) {
			e.printStackTrace();
		} 
		catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static SQLManager getSQLManager() {
		return sqlManager;
	}
	
	public static void init(String baseDir) {
		 sqlManager = new SQLManager(baseDir + "SQLStatements.sql");
	}
}

Entao voce chama init(“xxxx”) para iniciar o Singleton e entao o resto funciona normalmente, com voce chamando getSQLManager() para pegar a instancia.

Rafael

B
new SQLManager(System.getProperty("user.dir")  + "/SQLStatements.sql");
F

Rafael Steil:
Uma dica se alguem for quer usar LIKE: faca o sql

SELECT campoX FROM tabela WHERE outroCampo LIKE ?

e para atribuir o valor faca

....
pstmt.setString(1, "%valor%")

ou seja, passe as “%” pelo setXXX ao inves de colocar direto no sql

[]'s
Rafael Steil

Estou tentando fazer do jeito que está aqui mas tágerando uma excessão de SQL na hora de rodar o executeQuery.
Alguém pode me ajudar?

try{ ConectaBd cn = new ConectaBd(); QueryManager manager = QueryManager.getQueryManager(); ps = manager.getPreparedStatement(cn.getConnection(), "cliente.SelectLikeByName"); ps.setObject(1, "%Leandro%"); rs = ps.executeQuery(); while(rs.next()){ String[] linha = {rs.getString(0),rs.getString(1)}; tm.addRow(linha); } }catch(SQLException e){ JOptionPane.showMessageDialog(getContentPane(), "Erro ao conectar o Banco de Dados", "SQLException", JOptionPane.WARNING_MESSAGE); }

O arquivo properties tem o seguinte:

cliente.SelectLikeByName = select cpf,nome from clientes where nome like ?

Valew.

P

Paulo Silveira:
“bandrade”:
Pessoas, em java só é possível criar uma consulta dinamicamente usando ‘?’, não existe algo como deelphi em que vc dá nome aos campos??

té,

acho que o que esta perguntando eh se os prepared statements podem indexar as variaveis por nome, em vez de indices da posicao dos “?”, nao?

a resposta eh nao :frowning: Um preparedStatement como esse seria muito legal. muitas pessoas escrevem o proprio, ja que essa ideia eh melhor que setObject(1, x)

tem um exemplo aqui:

NamedPreparedStatement.java

sds

L

já deram uma olhada neste Framework.

http://code.google.com/p/krank/

Criado 29 de outubro de 2002
Ultima resposta 15 de jan. de 2008
Respostas 30
Participantes 16