Spring Framework Parte 3 -> Java Database Connectivity (JDBC)
Bem vindo leitor a mais um post da série Spring Framework.
Caso você ainda não leu os posts anteriores, por favor dê um pulinho bem rápido neles:
- Spring Framework Parte 1 -> Dependency Injection
- Spring Framework Parte 2 -> Aspect Oriented Programming
Vamos ao nosso próximo assunto então: JDBC e como o Spring facilita esse cara pra gente!
Tirando essa imagem do livro Spring in Action 2 (Manning, 2008) nós já conseguimos ver bem por cima como que o Spring pretende acessar de maneira padronizada a base de dados (Hitting the database) através de um objeto de acesso aos dados (DAO), um template (provido pelo próprio Spring) e caso nós quiséssemos, o Spring também oferece suporte padrão para alguns frameworks de persistência (será um dos próximos artigos desta série).
Tudo muito legal, muito bonito! Vamos tentar seguir este modelinho porque ele é bem bonitinho e vai nos ajudar um pouco. Apenas avisando que o jeito que descreverei neste tutorial não é o único jeito de acessar os dados através do seu driver JDBC, porém é um jeito que eu achei bem interessante e que vale a pena todos sabermos um pouquinho… =]
Existem apenas 2 conceitos básicos que o Spring nos sugere para o acesso rápido e fácil aos dados através de drivers JDBC: DataSource (DAO fornecido pelo Spring) e JdbcTemplate (template para acesso a dados através de um driver JDBC fornecido pelo Spring):
DataSource é uma classe provida pelo nosso querido Spring Framework e que se preocupa com toda a conexão e conversação com o driver JDBC que iremos utilizar (neste exemplo iremos utilizar o driver JDBC para o banco de dados MySQL). Em palavras um pouco mais técnicas, esta classe irá se resonsabilizar por nos entregar um objeto java.sql.Connection, java.sql.Statement, entre esses objetos que utilizamos quando o assunto é conexão de dados JDBC.
JdbcTemplate é uma outra classe muito útil provida pelo nosso adorado Spring! Este template provê métodos padronizados para acessarmos os dados (selecioná-los e manipulá-los), ou seja, fazer tudo o que podemos fazer com eles de um jeito bem fácil de acessar (como você irá descobrir logo a frente).
Muito bem, com esses dois conceitos já pintados na sua cabeça, por favor responda corretamente a próxima pergunta: “Já que estas classes são providas pelo nosso amigo Spring, quem instancia elas?”. Exato!! O próprio Spring cria os beans para estas classes, tudo o que temos que fazer é declarar estes beans no arquivo de configuração do Spring. Vamos a ele então:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost/spring_jdbc" /> <property name="username" value="root" /> <property name="password" value="123" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
Tão simples quanto encher um copo com água! Eu sinto até orgulho de mostrar como é fácil conectar com uma fonte de dados JDBC através do Spring!
O nosso primeiro bean é o dataSource. Como eu já disse ali em cima, esse é o cara responsável por conversar com o driver JDBC. Então nada mais justo que a gente ensinar ele a se comunicar com o driver passando os parâmetros corretos não é… Os parâmetros (injetados através da DI) passados para o dataSource foram: dataClassName (qual driver JDBC será usado), url (caminho do JDBC para se conectar até o banco de dados desejado), username (login do banco de dados) e password (senha do banco de dados).
No caso desse nosso exemplo, o driver JDBC é do MySQL, nunca esqueça que o driver deve estar no classpath em!!! Segue uma foto te ensinando como adicionar o driver JDBC do MySQL no NetBeans:
E o segundo bean do arquivo de configuração é o jdbcTemplate que é o template provido pelo Spring para facilitar a manipulação dos dados. A unica dependência que este bean tem é o próprio dataSource, ou seja, ele precisa de uma referência para um dataSource para saber em qual banco ele vai executar os comandos que quisermos. Sendo assim, de um jeito muito fácil (injeção de dependência), nós passamos uma referência do nosso dataSource já criado para ele. ^^
Só fazendo uma pequena pausa no Spring agora, vamos falar um pouquinho do banco de dados: criei uma tabela de Pessoas para fazermos nossos teste aqui. Dê uma olhada no script de criação:
CREATE TABLE `Pessoas` ( `pes_cod` INT NOT NULL , `pes_nome` VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL , `pes_idade` INT NOT NULL , PRIMARY KEY ( `pes_cod` ) ) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
Muuuito bem! A esta altura nós já temos os arquivos base para a conexão com o banco de dados E o banco de dados! Vamos continuar a codificar mais algumas classes e veremos o quão fácil o Spring tornou o acesso aos dados através do JDBC para nós.
Já que temos a tabela pronta no banco de dados, precisamos desenvolver uma classe Java que irá representar cada registro dessa tabela (para manipulação em memória né…):
Pessoa.java
public class Pessoa { private int cod; private String nome; private int idade; public Pessoa() { this.cod = -1; this.nome = "Não Encontrado"; this.idade = -1; } public int getCod() { return cod; } public void setCod(int cod) { this.cod = cod; } public int getIdade() { return idade; } public void setIdade(int idade) { this.idade = idade; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } @Override public String toString() { return "Codigo: " + String.valueOf(this.cod) + " | Nome: " + this.nome + " | Idade: " + String.valueOf(this.idade); } }
Pronto, com a classe Pessoa agora fica bem mais fácil nós termos uma “Pessoa” em memória! Vamos daqui pra frente tentar unir a classe Pessoa que acabamos de escrever com o banco de dados, ou seja, inserir um objeto da classe Pessoa no banco de dados, recuperar um objeto Pessoa do banco, e por ai vai…
Caso você acompanha este blog regularmente, já deve ter percebido que eu virei fã de utilizar as interfaces no desenvolvimento (os motivos são muitos! então apenas acredite: compensa!). Já que eu sou um cara que gosta de seguir padrões e tudo mais, vamos codificar uma interface que será muito útil para o nosso acesso ao banco de dados:
IBanco.java
public interface IBanco { public void InserirPessoa(Pessoa pessoa); public void AtualizarPessoa(Pessoa pessoa); public void ApagarPessoa(Pessoa pessoa); public Pessoa SelecionarPessoa(Pessoa pessoa); }
Esta interface obriga a classe que implementá-la a dar suporte para as operações CRUD referêntes aos objetos Pessoa juntamente com a tabela do banco de dados Pessoa (ficou meio confusa essa frase? hehehe).
Como o código sempre resolve tudo, vamos a ele que você irá entender do que eu estou falando:
BancoDados.java
public class BancoDados implements IBanco { private JdbcTemplate jdbcTemplate; public BancoDados() { } public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void InserirPessoa(Pessoa pessoa) { String sql = "INSERT INTO Pessoas(pes_cod,pes_nome,pes_idade) VALUES(?,?,?)"; jdbcTemplate.update(sql, new Object[]{pessoa.getCod(), pessoa.getNome(), pessoa.getIdade()}); } public void AtualizarPessoa(Pessoa pessoa) { String sql = "UPDATE Pessoas SET pes_nome = ?, pes_idade= ? WHERE pes_cod = ?"; jdbcTemplate.update(sql, new Object[]{pessoa.getNome(), pessoa.getIdade(), pessoa.getCod()}); } public void ApagarPessoa(Pessoa pessoa) { String sql = "DELETE FROM Pessoas WHERE pes_cod = ?"; jdbcTemplate.update(sql, new Object[]{pessoa.getCod()}); } public Pessoa SelecionarPessoa(Pessoa pessoa) { String sql = "SELECT * FROM Pessoas WHERE pes_cod = ?"; List resultados = jdbcTemplate.query(sql, new Object[]{pessoa.getCod()}, new RowMapper() { public Object mapRow(ResultSet rs, int i) throws SQLException { Pessoa p = new Pessoa(); p.setCod(rs.getInt("pes_cod")); p.setNome(rs.getString("pes_nome")); p.setIdade(rs.getInt("pes_idade")); return p; } }); Pessoa pes = new Pessoa(); if (resultados.size() > 0) { pes = (Pessoa) resultados.get(0); } else { pes.setCod(pessoa.getCod()); } return pes; } }
Muito bem, vamos com calma…
A primeira coisa que devemos notar é que temos uma variável de instância chamada jdbcTemplate. Como eu imagino que você leitor é um cara que associa tudo muito rápido e já viu que um pouco mais pra baixo dessa variável tem o setter dela, eu imagino que você já entendeu que essa variável vai ser injetada através do container do Spring né… =]
Como nós já pedimos pro Spring criar um bean do tipo JdbcTemplate no arquivo de configuração, daqui a pouco nós voltaremos nele e pediremos pra ele enviar uma referência do JdbcTemplate aqui pra essa nossa classe poder usar. Tudo muito prático!
Depois disso o que nós podemos entender é que a classe reescreveu os métodos que a interface obriga e os implementou de fato! Vamos entender eles rapidinho…
Para as operações de inserção, alteração e exclusão os métodos são absolutamente iguais: primeiro foi definido o SQL referente a operação e depois foi chamado o método update da nossa classe super amigável: jdbcTemplate.
Existem dois detalhes para chamar a atenção na execução destas operações:
1 – O SQL que foi montado não possui os valores finais. Ao invés deles estão presentes pontos de interrogação ( ? ) representando parâmetros.
2 – Os parâmetros informados no SQL são enviados como o segundo parâmetro do método update do jdbcTemplate. Para a padronização na chamada do método é necessário que todos os parâmetros definidos no SQL sejam passados dentro de um vetor de Object (mesmo que seja só um parâmetro, ele também deve estar dentro do vetor). Outra coisa que vale ser lembrada é que o primeiro item do vetor irá ser incluído no lugar do primeiro parâmetro do SQL (primeiro ponto de interrogação) então tome cuidado para passar os parâmetros na ordem correta para o vetor de Object.
Só mais um comentário para a operação de seleção: também foi utilizado um SQL com parâmetro e um vetor de Object referenciando os parâmetros porém o método do jdbcTemplate utilizado não foi o update, e sim o query!
O funcionamento deste método é bem interessante: ao invés de apenas 2 parâmetros (como no método update), depois do vetor de Object é passado um objeto org.springframework.jdbc.core.RowMapper que é responsável por mapear cada registro retornado por um ResultSet interno ao jdbcTemplate em um objeto correspondente ao registro e após o mapeamento o objeto customizado é adicionado a um java.util.List que é o retorno final do método query.
Exemplo do nosso caso: caso sejam retornadas 3 pessoas pelo SQL utilizado, o método mapRow do objeto RowMapper será invocado 3 vezes (uma para cada registro). Cada vez que ele for invocado será configurado um novo objeto Pessoa com os dados de cada registro retornado do banco de dados e cada vez que o método retornar um novo objeto Pessoa ele será guardado na lista que será retornada pelo método query.
Logo depois deste método eu apenas retorno o primeiro objeto que está na lista ou então retorno um objeto com o mesmo código da busca caso não foi encontrado nenhum registro.
Sempre muito simples esses códigos… adoro isso… ehheheh
Vamos adicionar um bean ao arquivo de configuração do Spring para o container também instanciar a nossa classe responsável pelo banco de dados e é claro, vamos também já injetar o JdbcTemplate no nosso novo bean:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost/spring_jdbc" /> <property name="username" value="root" /> <property name="password" value="123" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="banco_dados" class="spring_jdbc.BancoDados"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> </beans>
E isso é tudo!!
Nossas classes base para o acesso e manipulação da entidade Pessoa no banco de dados e no nosso próprio software já estão codificadas e bem funcionais. Tudo que precisamos agora é de um programinha exemplo para testarmos estas classes e ver como iriam ser realmente usadas.
Segue a classe que contém o método main desta aplicação:
public class Principal { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("/conf/spring_jdbc.xml"); BancoDados banco = (BancoDados) ctx.getBean("banco_dados"); //cria os objetos Pessoa Pessoa p1 = criar_pessoa(1, "Felipe", 18); Pessoa p2 = criar_pessoa(1, "Felipe Saab", 21); Pessoa felipe = null; //insere no banco try { banco.InserirPessoa(p1); System.out.println("1 - Pessoa Inserida"); } catch (Exception e) { System.out.println("Não foi possível inserir o registro: " + e); } //recupera try { felipe = banco.SelecionarPessoa(p1); System.out.println("2 - Pessoa recuperada: " + felipe); } catch (Exception e) { System.out.println("Não foi possível recuperar o registro: " + e); } //altera try { banco.AtualizarPessoa(p2); System.out.println("3 - Pessoa Atualizada"); } catch (Exception e) { System.out.println("Não foi possível atualizar o registro: " + e); } //recupera novamente try { felipe = banco.SelecionarPessoa(p2); System.out.println("4 - Pessoa recuperada: " + felipe); } catch (Exception e) { System.out.println("Não foi possível recuperar o registro: " + e); } //apaga try { banco.ApagarPessoa(p2); System.out.println("5 - Pessoa Apagada"); } catch (Exception e) { System.out.println("Não foi possível apagar o registro: " + e); } //procura pela ultima vez try { felipe = banco.SelecionarPessoa(p2); System.out.println("6 - Pessoa recuperada: " + felipe); } catch (Exception e) { System.out.println("Não foi possível recuperar o registro: " + e); } } public static Pessoa criar_pessoa(int cod, String nome, int idade) { Pessoa p = new Pessoa(); p.setCod(cod); p.setNome(nome); p.setIdade(idade); return p; } }
Concordo que o exemplo é meio grandinho mas é bem fácil de entender não é?
Primeiro foram criados 3 objetos Pessoa (p1 – “Felipe”, p2 – “Felipe Saab” e felipe que irá receber o resultado da busca no banco), depois foi inserido um dos objetos, procurado por ele no banco, depois ele foi alterado com as informações do outro objeto e foi recuperado novamente, e por fim a Pessoa foi apagada do banco e só para garantir foi feita uma última busca.
Este exemplo foi só para testar todas as operações que nós implementamos. Caso você use algo parecido no seu software do dia a dia irá ver que tudo funciona perfeitamente bem (cada operação no teu lugar certo).
É isso ai leitor! Você chegou ao fim deste post grandão!! ![]()
Espero que tenha gostado da leitura e da função que foi descrita aqui.
Caso queira fazer o download do projeto que eu desenvolvi como exemplo pode fazer o download aqui (OBS: o projeto está com bibliotecas do NetBeans 6.8 (Spring 2.5 e MySQL JDBC) então ele só vai rodar 100% certo caso você abra ele no NetBeans 6.8 ou superior, caso contrario, apenas aproveite os códigos fonte =] ).
[]s e até a próxima,
Saab.


20 Responses so far
Mikhas
setembro 2nd, 2010
10:49
Você poderia usar o Spring 3. Ele tem algumas coisinhas minimas que deixam o código mais elegante
Saab
setembro 2nd, 2010
11:45
Então Mikhas,
Eu estou escrevendo uma base mais sólida sobre o que tinha antes do Spring 3 para depois fazer uns posts legais sobre as novidades e facilidades do Spring 3.
Vai ser bem legal.. =]
Jb
setembro 22nd, 2010
17:45
Muito bom o tutorial, parabéns !
Flavio
outubro 23rd, 2010
21:34
Como controlar a transação utilizando o jdbcTamplate?
Saab
outubro 24th, 2010
9:28
Então Flavio,
Falar sobre transações pede um novo post…
Dei uma procurada rápida no google e achei o que você está procurando: http://sujitpal.blogspot.com/2007/03/spring-jdbctemplate-and-transactions.html
Daqui algum tempo aparece um post sobre transações por aqui.
felipe
maio 6th, 2011
1:36
Eu ia perguntar exatamente sobre as transações, utilizei jdbcTemplate no trabalho e não faziamos injeção, criava no datasource com parametros de um arquivo de configuração iniciava transação e no final do aplicativo, comitava e fechava…
Parabéns pelo post!
johnbri
maio 19th, 2011
23:03
pq nao integra JPA ou jpa e hibernate?
hj em dia acho q fazer uma aplicacao web d medio porte p cima e nao usar jpa tendo q escrever queries em strings chega a doer o coracao.
se questao for extrema performance tente adicionar C3p0 com hibernate…
mas meu ponto eh q msm p uma aplicacao d testes fica mt mais facil e limpo cm JPA…
configura o spring, injeta o entityManager ou o entityManagerFactory e usa, sem queries manais p/s coisas usuais.
—
eh uma sugestao…
d qqer forma a configuracao do spring q eh o principal tah show vlw
Saab
maio 21st, 2011
13:50
Ooo rapaz,
Esse é o próximo post da série (que por sinal já está escrito hehe): http://www.javasimples.com.br/spring-2/spring-framework-parte-4-integracao-com-o-hibernate/
[]
Vinicius
agosto 3rd, 2011
11:46
Estou lendo todos esses tutoriais da série Spring. Todos muito bons, to começando a entender como funciona o negócio.
Muito bom.
Abraço!
Anderson
outubro 21st, 2011
11:59
Cara, parabens pelo posts show de bola mesmo. to começando a entender como funciona o spring na pratica.
valeu !! .
Marcos
janeiro 30th, 2012
11:57
Muito bom o teu tutorial! Parabéns!
Afonso '
fevereiro 28th, 2012
17:30
Parabéns, ajudou muito.
Estou com um problema, como resolvo a situação da coluna no banco ser auto increment? (como deve ficar minha String sql?)
Muito obrigado,
Deus lhe abençoe.
Felipe Saab
fevereiro 28th, 2012
18:18
Basta não colocar a sua coluna no sql, simplesmente omita ela, o banco vai cuidar de atribuir um valor.
Afonso '
fevereiro 29th, 2012
15:05
Obrigado, deu certo!
Eu estou lendo pesquisando sobre desenvolvimento em modulos para consegui o maior nivel de abstração entre eles.
Valeria a pena começar um projeto grande(pessoal) para possibilitar uma mudança de cada um (model, view e controller) ?
Felipe Saab
fevereiro 29th, 2012
16:27
Para ser bem sincero eu não entendi…
Caso queira discutir esse assunto me envie um e-mail, só pra ficar evitando essas discussões mais específicas aqui nos comentários…
[]s
Elizeu Santos
abril 3rd, 2012
23:19
tu é o cara!
só por curiosidade… está empregado?
Elizeu Santos
abril 4th, 2012
7:31
putz meu, adepto do C# descoberto!!!
IBanco e métodos iniciando com letra maiuscula!!
Felipe Saab
abril 4th, 2012
13:28
Esse post foi na época da faculdade ainda, dá um desconto poxa… hahahahah
Elizeu Santos
abril 5th, 2012
7:58
kkkkk

cara quero elogiar novamente,
seus posts estão MUITO bons.
espero que chegue logo a parte 8 rsrs, apesar de eu estar na 3 agora. estou devagar por que a demanda esta muito grande…
MARCIO DURAN
abril 19th, 2012
16:11
Ficou bom o tutorial, espero que seja publicado mais novidades em breve !
Leave a comment