Você está na página 1de 3

GUJ - Retirando o SQL do seu cdigo Java

http://www.guj.com.br/articles/115

GUJ

Retirando o SQL do seu cdigo Java


em 29/10/2002 , por Paulo Silveira
Introduo
Uma das boas prticas de programao, no s em java,
diminuir ao mximo o uso de Strings literais no seu cdigo
fonte, tcnica conhecida como "hardcoding". Um "antipadro"
de programao. Porque isto ruim? Bem, primeiro que voc
fica dependendo de recompilar o cdigo se precisar mudar
alguma coisa. Segundo que fica difcil voc achar um
mispelling (erro na hora de digitar) de uma String literal, e
terceiro que terrvel ler Strings e magic numbers no cdigo
de uma pessoa. O que Magic Number?
view plaincopy to clipboardprint?
1.
2.
3.

if (this.codigo == 47) {
// faca algo
}

O nmero 47 no representa nada para ningum, e esse cdigo fica difcil de ser lido. Imagine agora com uma
constante:
view plaincopy to clipboardprint?
1. if (this.codigo == DATABASE_ACCESS_ERROR) {
2.
// faca algo
3. }
O mesmo acontece para Strings literais. Claro que em java voc utilizaria Exceptions ao invs de cdigo de
erros, isto foi apenas um exemplo. Neste tutorial, aprenderemos a tirar as strings SQLs "hardcodadas" no
seu .java, de maneira elegante e eficiente. Para isto, necessrio voc ter um conhecimento bsico de JDBC e
conhecer a java.util.Properties (ou leia a API!). Uma vantagem enorme de retirar o seu SQL do .java, que
assim voc torna a sua aplicao quase que indepedente de banco de dados (se voc tomar bastante cuidado, vira
100% independente). Voce pode mudar em um arquivo de configuracao as SQLs, por exemplo, de TOP para
LIMITm diferena clssica entre alguns banco de dados!
PreparedStatement
java.sql.PreparedStatement uma interface que extende a interface Statement. A grande maioria dos drivers
JDBCs atuais suportam a utilizao desta interface. O que ela faz? Bem, vamos dar um exemplo concreto, para
irmos explicando:
view plaincopy to clipboardprint?
1. Connection conn = DriverManager.getConnection("jdbc:banco...");
2.
3. PreparedStatement pstmt = con.prepareStatement
("UPDATE EMPLOYEES SET SALARY = ? WHERE ID = ?");
4.
5. pstmt.setBigDecimal(1, 153833.00)
6. pstmt.setInt(2, 110592)
Este o exemplo que est na prpria API. O que ele faz? Primeiro ele pega uma conexo com o banco de dados,
exatamente como sempre fizemos. Depois, ele devolve um PreparedStatement a partir de um SQL meio
estranho: ele possui pontos de interrogao onde queremos reutilizar a SQL query. Para substituir esses pontos
de interrogao, basta usar um dos vrios mtodos setters que a interface PreparedStatement lhe oferece.

GUJ - Retirando o SQL do seu cdigo Java

http://www.guj.com.br/articles/115

Lembre-se que o setter recebe um inteiro, indicando qual ponto de interrogao ser utilizado: o primeiro vale 1,
diferente de indices de arrays que comeam com 0 em java. Chamado o setter, o driver JDBC vai dar um jeito
de traduzir aquele objeto/valor primitivo para dentro da SQL. Se voc colocar uma String, no precisa por as
aspas!!! Porque? Pois o driver JDBC cuida disso:
view plaincopy to clipboardprint?
1. PreparedStatement pstmt = con.prepareStatement("select * from usuario where name = ?");
2.
3. // no precisa de escape no '
4. pstmt.setString(1,"Joozinho D'a Silva");
Uma maneira muito comum de utilizar o PreparedStatement, usar o mtodo setObject. Este mtodo vai fazer
vrios instanceof e descobrir como deve colocar esse valor na sua SQL. Caso ele no descubra, ele vai chamar
o toString deste mtodo. Continuando o primeiro caso:
view plaincopy to clipboardprint?
1. pstmt.setObject(1, new Long(5000));
2. pstmt.setObject(2, new Integet(333));
Se voc tentar setar um ndice que no exista vai receber uma RuntimeException. Por exemplo, no nosso caso,
setObject(3,...) iria resultar em uma RuntimeException, indicando que no existe o 3o ponto de interrogao na
SQL dada! Para executar o PreparedStatement, idntnico ao Statement. Lembre-se de "setar" tudo antes de
execut-lo, ou voc receber uma exceo:
view plaincopy to clipboardprint?
1. ResultSet rs = pstmt.executeQuery(); // sem passar argumento!
O que mais o PreparedStatement responsvel por fazer?
Fazer o escape das aspas, aspas simples, e do prprio caractere de escape - isso muito til;
Traduzir muitos objetos para o formato String correspondente com o do banco de dados, como o
java.util.Date por exemplo, e o java.io.InputStream, que eu considero o mais til de todos: fica muito fcil
utilizar um campo Blob com um PreparedStatement. Antes que algum pergunte, o driver de JDBC para o
mysql tem sim, suporte a PreparedStatement. Alis, o GUJ usa e abusa deste recurso, inclusive para guardar as
imagens no banco de dados em BLOBs. Aqui voc j tem uma idia legal de como aproveitar o
PreparedStatement, mas sugiro que voc conhea a api dele, clicando aqui.
Arquivo de Configurao
Aps aprendermos a usar o PreparedStatement, vamos fazer algo para retira-los do seu .java. Para isso, vamos
passar todas as Strings que representam uma SQL para um arquivo de Properties, algo do tipo:
view plaincopy to clipboardprint?
1. usuario.selectByName=select * from usuario where name = ?
2. usuario.selectByEmail=select * from usuario where email = ?
Ento, ao invs de criarmos o PreparedStatement a partir de um String literal, ns pegamos ele a partir deste
arquivo Properties. Um esboo:
view plaincopy to clipboardprint?
1. Properties queries = new Properties();
2. queries.load("arquivoMysql.txt");
Na hora de criar um PreparedStatement, voc faz assim:
view plaincopy to clipboardprint?
1. PreparedStatement ps = connection.prepareStatement(queries.getProperty
(USUARIO_SELECT_BY_NAME));
Onde USUARIO_SELECT_BY_NAME uma constante: uma String static final e pblica. Porque isso? evitar

GUJ - Retirando o SQL do seu cdigo Java

http://www.guj.com.br/articles/115

o hardcoding e erros de execuo. Com isso, voc no ter mais nenhum SQL dentro do seu .java, o que um
grande passo. Vamos melhorar nosso esboo de como controlar essa properties que contm os SQLs.
O Singleton que controla tudo
Vamos criar aqui uma classe (esboo novamente) para controlar essa properties que tem as SQLs. No podemos
ficar lendo do arquivo texto toda vez que pegarmos uma SQL, precisamos de uma classe (instncia dela) para
fazer isso. Voc no precisa saber o que um Singleton. basicamente uma soluo para voc no fazer uma
classe que tenha tudo static, desta maneira, voc perderia a orientao a objetos.
view plaincopy to clipboardprint?
1. public class QueryManager {
2.
3.
protected Properties queries;
4.
5.
// nao deveria estar hardcodado:
6.
protected static queryManager = new Querymanager("arquivoMysql.txt");
7.
8.
private QueryManager(String arquivo) {
9.
queries = new Properties();
10.
// le as sqls e guarda!
11.
queries.load(new FileInputStream(arquivo));
12.
}
13.
14.
...
15.
16. }
At aqui temos o padro singleton implementado, mas vamos adicionar o mtodo que retorna um
PreparedStatement, dado uma conexo e o nome do statement que voc quer!
view plaincopy to clipboardprint?
1. public PreparedStatement getPreparedStatement
(Connection conn, String queryName) throws SQLException {
2.
String query = this.queries.getProperty(queryname);
3.
return conn.prepareStatement(query);
4. }
Cuidado: este mtodo pode dar NullPointerException no caso da query requerida no existir no arquivo de
configurao! Para utilizar esta classe:
view plaincopy to clipboardprint?
1.
2.
3.
4.
5.

QueryManager manager = QueryManager.getQueryManager();


PreparedStatement ps = manager.getPreparedStatement(conn, USUARIO_SELECT_BY_NAME);
ps.setString(1, "Joaozinho"); // poderia ser setObject, recomendo!
ResultSet rs = ps.executeQuery();

Simples no? No tenha medo do singleton, a nica coisa que ele faz impedir que exista mais de uma instncia
desta classe por ClassLoader.
Concluso
Este tutorial foi realizado devido a muitos pedidos de como retirar o SQL do codigo java. Voc pode refinar o
processo, utilizando XML no caso que voc tenha uma hierarquia entre as SQLs. O problema seria escrever um
parser apenas para este arquivo de configuraes. Voc ainda pode melhorar essa soluo: utilizando alguma
biblioteca/ferramenta que possibilite o "mapeamento objeto relacional". Usar uma ConnectioPool tambm
muito til! Espero que tenha ficado claro a melhoria que voc ganha a partir do momento que para de lidar com
literais: maior reuso do cdigo, melhor leitura, maior adaptao e facilidade de reescrita. E claro: quem no
gosta de um arquivinho de configuraes :).
ALURA
Cursos online de tecnologia
CAELUM

Você também pode gostar