Você está na página 1de 42

Java e Banco de Dados JDBC

On-Line

Java e Banco de Dados JDBC On-Line

Todos os direitos reservados para Alfamdia Prow


AVISO DE RESPONSABILIDADE
As informaes contidas neste material de treinamento so distribudas NO ESTADO
EM QUE SE ENCONTRAM, sem qualquer garantia, expressa ou implcita. Embora
todas as precaues tenham sido tomadas na preparao deste material, a Alfamdia
Prow no tem qualquer responsabilidade sobre qualquer pessoa ou entidade com
respeito responsabilidade, perda ou danos causados, ou alegadamente causados, direta
ou indiretamente, pelas instrues contidas neste material ou pelo software de
computador e produtos de hardware aqui descritos.

01/2012 Verso 1.0.68

Alfamdia Prow
http://www.alfamidia.com.br

Java e Banco de Dados JDBC On-Line

Sumrio
Captulo 1 O Bsico ........................................................................................ 4
Criando Um Banco de Dados de Exemplo................................................................................ 4
Drivers JDBC ............................................................................................................................ 5
Instalando o Driver no seu Projeto ........................................................................................ 5
A Rotina de Uso da API JDBC ............................................................................................... 10

Captulo 2 Preparando para Usar o Banco de Dados .................................... 11


Registrando um Driver JDBC ................................................................................................. 11
A Classe DriverManager ..................................................................................................... 11
Conectando a um Banco de Dados .......................................................................................... 12
A Interface Connection ....................................................................................................... 12

Captulo 3 Usando Queries Simples ............................................................. 14


A Interface Statement .............................................................................................................. 14
A Interface ResultSet .............................................................................................................. 15
A Interface ResultSetMetaData ............................................................................................... 18

Captulo 4 Usando Queries Pr-Compiladas ................................................ 20


A Interface PreparedStatement................................................................................................ 20

Captulo 5 Usando Chaves de Auto-Incremento........................................... 23


Captulo 6 Utilizando Stored Procedures ...................................................... 25
A Interface CallableStatement ................................................................................................ 25
Um Stored Procedure Que Retorna um ResultSet............................................................... 27
Um Stored Procedure Que Recebe um Parmetro e Retorna um ResultSet ........................ 28
Um Stored Procedure Que Retorna um Inteiro ................................................................... 29
Um Stored Procedure Que Tem Um Parmetro de Entrada e Sada ................................... 30

Captulo 7 Usando o Design-Pattern DAO ................................................... 33


A Classe de Bean .................................................................................................................... 34
A Classe DAOException......................................................................................................... 37
A Classe DAO ......................................................................................................................... 37
A Classe PessoaDAO .............................................................................................................. 38

Java e Banco de Dados JDBC On-Line

Captulo 1 O Bsico

JDBC significa Java Database Connectivity (conectividade com bancos de dados em Java).
uma API para a Linguagem Java que define como um cliente pode acessar um banco de dados.
A API focada em bancos de dados relacionais e foi lanada em 19 de Fevereiro de 1997, como
parte do Java Development Kit 1.1.
Embora a plataforma j tenha nascido preparada para lidar com todo tipo de banco de dados
relacional, na poca era oferecida apenas uma implementao de referncia da Bridge ODBCJDBC, o que permitia que programas escritos em Java acessassem qualquer fonte de dados
ODBC ao alcance do ambiente hospedeiro da JVM.
JDBC permite que mltiplas implementaes coexistam e possam ser usadas na mesma
aplicao. A API prov um mecanismo para carregar dinamicamente os pacotes Java
necessrios conexo com um determinado banco de dados e para registrar estes pacotes frente
classe DriverManager, que usada como Factory para se obter as conexes com os mesmos.
As instrues suportadas incluem CREATE, INSERT, UPDATE, DELETE e SELECT. H
inclusive a possibilidade de se chamarem Stored Procedures.

Criando Um Banco de Dados de Exemplo


Para que possamos exercitar os conhecimentos adquiridos neste livro vamos precisar criar um
banco de dados. Usaremos como base o MySQL, mas se voc quiser pode experimentar com
qualquer outro banco relacional.
Usando as suas ferramentas de banco de dados preferidas, crie um novo banco de dados
chamado AgendaTelefonica. L dentro crie uma tabela chamada Pessoa. Se quiser, crie
ainda um usurio chamado agenda com senha agenda e lhe d plenos poderes.
Voc pode o script abaixo como exemplo:
CREATE DATABASE AgendaTelefonica CHARACTER SET=latin1
COLLATE=latin1_general_ci;
USE AgendaTelefonica;
CREATE TABLE Pessoa (
Id
int(8)
NOT NULL AUTO_INCREMENT PRIMARY KEY,
Nome
varchar(40) NOT NULL,
Endereco varchar(200) NULL,
Cidade
varchar(40) NULL,
Estado
char(2)
NULL,
CEP
char(9)
NULL,
Ddd
char(2)
NOT NULL,
Telefone char(9)
NOT NULL
);
4

Java e Banco de Dados JDBC On-Line

CREATE USER agenda@localhost IDENTIFIED BY 'agenda';


GRANT ALL ON *.* TO agenda@localhost;

Drivers JDBC
Os Drivers JDBC so adaptadores instalados no lado cliente que convertem as requisies feitas
por meio da API JDBC para um protocolo capaz de ser entendido pelo banco de dados de
destino.
Existem drivers comerciais e gratuitos para os mais diversos formatos de bancos de dados.
Cada um destes drivers cai em uma das quatro categorias disponveis:

Tipo 1
Tipo 2
Tipo 3
Tipo 4

Tipo

Nome

Java Puro

Protocolo de Rede

Descrio

Tipo 1

Bridge
ODBC

Direto

Chama cdigo nativo


de um banco ODBC
disponvel localmente

Tipo 2

API Nativa

No

Direto

Chama cdigo nativo


do
fornecedor
do
banco.
Este cdigo
ento fala com o banco
por meio da rede.

Tipo 3

JDBC Net

Sim

Requer Conector

Cdigo Java puro que


fala com o middleware
do banco e ento com
o banco.

Tipo 4

Direto

Sim

Direto

Driver em Java puro


que usa o protocolo
nativo do banco.

JDBC- No

Instalando o Driver no seu Projeto


Para que voc possa desenvolver uma aplicao que utiliza JDBC voc precisar encontrar e
baixar o driver especfico para o seu banco de dados. Em virtualmente todos os casos os drivers
estaro disponveis na rea de download do fabricante do seu banco de dados.
Depois de completar o download voc precisar colocar o driver no classpath para que ele esteja
disponvel para o compilador e o run-time do Java. Nas pginas a seguir exibiremos a rotina
para o MySQL, mas o processo basicamente o mesmo para qualquer banco de dados.
Comece acessando o site do MySQL, http://www.mysql.com . Depois clique em Downloads.
Rolando a tela voc encontrar o link para o Connector/J, como mostrado na figura abaixo.

Java e Banco de Dados JDBC On-Line

Conector/J o nome comercial do driver JDBC do MySQL. Clique em DOWNLOAD para baixlo.

Quando a prxima pgina surgir, escolha o formato que lhe mais conveniente (tipicamente,
usurios do Windows escolhero o formato .zip, enquanto que usurios do Linux escolhero o
formato .tar).
Salve o arquivo em um diretrio do seu disco rgido, por exemplo, e depois, usando o Windows
Explorer, navegue at aquele local.

Java e Banco de Dados JDBC On-Line

Abra o arquivo que voc baixou com um descompactador de sua preferncia.

L dentro voc encontrar um arquivo mysql-connector-java-<verso>-bin.jar.


Extraia-o para um diretrio de sua preferncia. Este o nico arquivo de que precisamos, mas
se voc quiser pode extrair todo o contedo do arquivo .zip para algum diretrio e explor-lo.
O diretrio docs, por exemplo, est cheio de documentao e exemplos de cdigo que so
bastante teis.

Java e Banco de Dados JDBC On-Line

O arquivo .jar que extramos o arquivo que contm as classes Java que so necessrias para
conectar a um banco de dados MySQL. Com o arquivo salvo em algum lugar, agora hora de
acrescent-lo ao seu projeto. Nas imagens abaixo mostraremos o processo usando o NetBeans,
nas o processo no muito diferente se voc estiver usando outro IDE, como o Eclipse por
exemplo.
Depois de abrir o NetBeans e criar o seu projeto, clique com o boto direito sobre ele no Project
Explorer e selecione a opo Propriedades. Com a janela Propriedades do projeto
aberta, clique em Bibliotecas. Voc ver algo parecido com a tela mostrada abaixo.

Java e Banco de Dados JDBC On-Line

Agora clique no boto Adicionar JAR/pasta para que possa selecionar o arquivo .jar
que extramos.

Navegue at o diretrio onde voc salvou o arquivo .jar e selecione-o, clicando em Abrir
em seguida.

Java e Banco de Dados JDBC On-Line

Pronto, a biblioteca JDBC do MySQL est agora disponvel em seu projeto.

A Rotina de Uso da API JDBC


As classes da API JDBC esto no pacote java.sql. Alm dessas voc vai precisar das
classes que implementam o driver para o seu banco de dados especfico (a no ser que esteja
usando a Bridge JDBC-ODBC).
Os drivers precisam se registrar com a classe DriverManager para que possamos nos utilizar
dos seus servios. A partir do JDBC 4.0 (Java 6) esta operao feita automaticamente,
bastando que um driver compatvel esteja no CLASSPATH.
DriverManager a classe que identifica qual o melhor driver a utilizar para se conectar com
um determinado banco de dados.
Uma aplicao JDBC tpica desempenhar as seguintes operaes quando consultando dados no
banco:

Registrar o driver junto ao DriverManager;


Obter uma conexo junto ao banco de dados;
Efetuar uma query ou enviar um comando para o banco de dados;
Opcionalmente, iterar por entre os resultados obtidos;
Efetuar a desconexo.

10

Java e Banco de Dados JDBC On-Line

Captulo 2 Preparando para Usar o


Banco de Dados

Neste captulo veremos um pouco do que necessrio para que possamos criar aplicaes que
utilizem a API JDBC.

Registrando um Driver JDBC


A Classe DriverManager
Como dito anteriormente, a classe java.sql.DriverManager que sabe qual o driver que
melhor atende a um determinado tipo de banco de dados. Quando os drivers se registram frente
ao DriverManager eles informam o seu tipo e a que banco so capazes de atender.
Isto possibilita que, quando solicitamos uma conexo, no precisemos informar o driver a
utilizar: basta indicar a URL do banco e o DriverManager faz o resto por ns.
try {
Class.forName("<classe-de-driver>");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
}
No exemplo acima, <classe-de-driver> o nome completamente qualificado da classe
que implementa o driver para o seu banco especfico. No caso do MySQL este driver se chama
com.mysql.jdbc.Driver. Outros bancos, obviamente, tero classes diferentes.
Se esta classe porventura no for encontrada no classpath da aplicao uma
ClassNotFoundException ser lanada. Voc poder capturar esta exceo para
informar ao usurio do ocorrido, ou para armazenar esta informao no log. Obviamente, se
este erro ocorrer nenhum cdigo que faz acesso ao banco de dados funcionar.
RegistrandoODriver.java
public class RegistrandoODriver {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
}
}
}

11

Java e Banco de Dados JDBC On-Line

Carga Automtica do Driver JDBC


A partir da verso 4.0 da API JDBC (includa a partir do Java SE 6) no precisamos mais incluir
explicitamente o driver do banco. O DriverManager ter a responsabilidade de procurar em
todos os JARs da aplicao por drivers JDBC. O arquivo JAR de um Driver JDBC deve possuir
o arquivo META-INF/services/java.sql.Driver, o qual indicar o nome da classe
Java que implementa o Driver JDBC.

Conectando a um Banco de Dados


A Interface Connection
A interface java.sql.Connection representa uma conexo (uma sesso) frente a um
banco de dados: comandos SQL e resultados so retornados dentro do contexto de uma
conexo.
Obtm-se um objeto do tipo Connection ao se chamar o mtodo getConnection() da
classe abstrata DriverManager, passando como argumentos a URL do banco de dados qual
se deseja conectar, o nome e a senha de um usurio com autorizao para acess-lo.
Um objeto do tipo Connection capaz de obter informaes a respeito do banco ao qual est
conectado, como por exemplo:
A gramtica suportada;
Suas tabelas;
Seus stored procedures;
Etc.
try {
Connection con = DriverManager.getConnection(
<url>, <usurio>, <senha>);
} catch (SQLException sqle) {
System.out.println(
Incapaz de conectar.);
}
No exemplo acima, <url> a URL de conexo com o banco de dados; j os atributos
<usurio> e <senha> representam o par nome de usurio e senha, e oferecem as
credenciais para acesso ao servidor de banco de dados.
A tabela abaixo apresenta os mtodos mais importantes definidos pela interface
java.sql.Connection:
Mtodo

Descrio

void close()

Encerra esta conexo.

void commit()

Persiste todas as mudanas feitas desde o


ltimo commit ou rollback.

Statement createStatement()

Cria um objeto do tipo Statement para enviar


comandos ao banco de dados.

boolean isClosed()

Identifica se esta conexo est fechada ou no.


Se a conexo estiver fechada no
conseguiremos executar qualquer query ou
outra operao de banco.
12

Java e Banco de Dados JDBC On-Line

Mtodo

Descrio

boolean isReadOnly()

Identifica se esta conexo de apenas leitura


ou no.

boolean isValid()

Identifica se esta conexo est efetivamente


conectada a um banco de dados e se continua
vlida.

CallableStatement prepareCall(String sql)

Cria um objeto do tipo CallableStatement para


chamar stored procedures do banco.

PreparedStatement
sql)
void rollback()

prepareStatement(String Cria um objeto do tipo PreparedStatement


para enviar comandos SQL pr-compilados
para o banco de dados.
Desfaz todas as mudanas feitas desde o
ltimo commit / rollback.

ConectandoAoBanco.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConectandoAoBanco {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
return;
}
Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost/agendatelefonica",
"agenda", "agenda");
// Voc colocaria aqui o cdigo que faz uso do banco.
} catch (SQLException sqle) {
System.out.println("Incapaz de conectar.");
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ignore) {
// Nada a fazer.
}
}
}
}

13

Java e Banco de Dados JDBC On-Line

Captulo 3 Usando Queries Simples

Java oferece trs interfaces principais para enviar comandos ao banco de dados:

Statement
PreparedStatement
CallableStatement

Instncias delas so obtidas atravs de chamadas a mtodos especficos do objeto Connection


utilizado para conectar ao banco de dados.
Neste captulo veremos a mais simples delas, Statement, mas nos prximos captulos
falaremos de PreparedStatement e CallableStatement.

A Interface Statement
Objetos do tipo java.sql.Statement so criados ao se chamar o mtodo
createStatement() do objeto Connection.
Objetos deste tipo so usados para executar comandos SQL estticos e obter os resultados que
eles produzem, seja por meio de valores primitivos ou por meio de um objeto
java.sql.ResultSet (primitivos so retornados quando o comando em questo apenas
informa o sucesso ou o nmero de registros afetados; um ResultSet retornado quando uma
query retorna o grupo de registros selecionados pelo seu critrio de filtro).
Os mtodos abaixo podem ser utilizados:
Mtodo

Descrio

void close()

Encerra esta Statement.

ResultSet executeQuery(String sql)

Executa o SQL indicado e retorna o ResultSet


resultante.

int executeUpdate(String sql)

Executa o SQL indicado (que pode ser um


INSERT, UPDATE ou DELETE, ou mesmo
um comando DDL) e retorna o nmero de
registros afetados (ou 0 se o comando no
afetou nenhum registro).

ResultSet getGeneratedKeys()

Retorna um ResultSet que indica as chaves


geradas ao se executar a Statement.

boolean isClosed()

Indica se esta Stetement est fechada ou no.

FazendoUmInsert.java
import java.sql.Connection;
14

Java e Banco de Dados JDBC On-Line

import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class FazendoUmInsert {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
return;
}
Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost/agendatelefonica",
"agenda", "agenda");
Statement stmt = con.createStatement();
int incluidos = stmt.executeUpdate(
"insert into pessoa(nome, ddd, telefone) "
+ "values ('Joo Silveira', '51', "
+ "'3030-1313')");
} catch (SQLException sqle) {
System.out.println("Erro de SQL: " + sqle);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ignore) {
// Nada a fazer.
}
}
}
}

A Interface ResultSet
Um ResultSet agrega os dados recuperados a partir do banco de dados em uma estrutura
semelhante a um iterator de uma coleo. Ele geralmente obtido por meio de instrues que
consultam o banco, como as Statement e PreparedStatement, mas tambm pode ser
retornado por instncias de CallableStatement.
O ResultSet possui um cursor que aponta para a linha corrente dentro da lista de resultados.
Este cursor inicialmente est posicionado na linha anterior primeira linha de dados.
Normalmente ResultSets so navegveis apenas para a frente e no so atualizveis.
Mtodos factory especiais em Connection permitem que ResultSet navegveis e
atualizveis sejam criados, mas eles normalmente consumem muito mais recursos do banco e
no so muito utilizados.
Apenas um ResultSet pode estar aberto por cada Statement, PreparedStatement ou
CallableStatement, ento mltiplos objetos sero necessrios no caso de se fazerem
consultas encadeadas.
15

Java e Banco de Dados JDBC On-Line

Um ResultSet automaticamente fechado quando o objeto Statement,


PreparedStatement ou CallableStatement que o gerou fechado, re-executado ou
usado para recuperar o prximo resultado dentro de uma sequncia de mltiplos resultados.
A tabela a seguir mostra alguns dos mtodos mais importantes da interface ResultSet.
Mtodo

Descrio

int findColumn(String columnLabel)

Retorna o ndice da coluna indicada.

BigDecimal
parameterIndex)

getBigDecimal(int Recupera o valor da coluna de ndice


indicado.

Blob getBlob(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

boolean getBoolean(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

byte getByte(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

Date getDate(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

double getDouble(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

float getFloat(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

int getInt(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

long getLong(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

ResultSetMetaData getMetaData()

Retorna um objeto ResultSetMetaData com


informaes a respeito das colunas retornadas
por este ResultSet,

Boolean getMoreResults()

Obtm o prximo grupo de resultados deste


CallableStatement e retorna True se ele um
ResultSet.

Object getObject(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

int getRow()

Recupera o nmero da linha atual.

short getShort(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

String getString(int parameterIndex)

Recupera o valor da coluna de ndice


indicado.

Timestamp
parameterIndex)
boolean isAfterLast()

getTimestamp(int Recupera o valor da coluna de ndice


indicado.
Indica se o cursor est posicionado alm da
ltima linha recuperada por este ResultSet.
16

Java e Banco de Dados JDBC On-Line

Mtodo

Descrio

boolean isBeforeFirst()

Indica se o cursor est posicionado antes da


primeira linha recuperada por este ResultSet.

boolean isClosed()

Indica se este ResultSet est fechado.

boolean isFirst()

Indica se o cursor est posicionado na


primeira linha recuperada por este ResultSet.

boolean isLast()

Indica se o cursor est posicionado na ltima


linha recuperada por este ResultSet.

boolean next()

Move o cursor uma linha para frente e retorna


True se ainda no ultrapassou o final da lista
de resultados.

FazendoUmSelect.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class FazendoUmSelect {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
return;
}
Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost/agendatelefonica",
"agenda", "agenda");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select id, nome "
+ "from pessoa order by nome, id");
while (rs.next()) {
System.out.print(rs.getInt("id"));
System.out.print(": ");
System.out.println(rs.getString("nome"));
}
} catch (SQLException sqle) {
System.out.println("Erro de SQL: " + sqle);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ignore) {
// Nada a fazer.
}
17

Java e Banco de Dados JDBC On-Line

}
}
}

A Interface ResultSetMetaData
Por meio da interface ResultSetMetaData pode-se descobrir a quantidade e tipo de dados
de cada coluna que seria/foi retornada por uma query. Com isso poderamos criar utilitrios ou
programas que lidam com dados sobre os quais nada se sabe de antemo, exatamente como o
PHPMyAdmin ou o Navicat fazem.
Obtm-se um ResultSetMetaData ao se chamar o mtodo getMetaData() de uma
instncia de PreparedStatement, CallableStatement ou ResultSet.
A tabela abaixo exibe os mtodos mais utilizados em ResultSetMetaData:
Mtodo

Descrio

String getCatalogName(int column)

Retorna o nome do catlogo que armazena a


tabela qual a coluna indicada pertence.

String getColumnClassName(int column)

Retorna o nome qualificado da classe Java


que seria usada para retornar a coluna
indicada se o mtodo getObject() fosse
chamado.

int getColumnCount()

Retorna o nmero de colunas deste objeto


ResultSet.

String getColumnLabel(int column)

Retorna o label definido para a coluna


indicada.

String getColumnName(int column)

Retorna o nome da coluna indicada.

int getColumnType(int column)

Retorna o tipo de dados da coluna indicada,


conforme os valores em java.sql.Types.

String getColumnTypeName(int column)

Retorna o nome do tipo de dados da coluna


indicada, conforme o banco de dados usado.

int getPrecision(int column)

Retorna o tamanho da coluna indicada. Para


colunas do tipo caractere isto equivale ao
comprimento da coluna, enquanto que para
dados numricos esta a parte inteira.

int getScale(int column)

Retorna o nmero de casas decimais da


coluna indicada.
Para colunas do tipo
caractere o valor ser sempre zero.

String getSchemaName(int column)

Retorna o nome do esquema da coluna


indicada.

String getTableName(int column)

Retorna o nome da tabela da coluna indicada.

Veja o exemplo abaixo:


BuscandoOsMetaDados.java
import java.sql.Connection;
import java.sql.DriverManager;
18

Java e Banco de Dados JDBC On-Line

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql. Statement;
public class BuscandoOsMetaDados {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
return;
}
Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost/agendatelefonica",
"agenda", "agenda");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select id, nome "
+ "from pessoa order by nome, id");
ResultSetMetaData rsmd = rs.getMetaData();
int numeroDeCampos = rsmd.getColumnCount();
for (int i = 1; i <= numeroDeCampos; i++) {
System.out.print(rsmd.getTableName(i));
System.out.print(".");
System.out.print(rsmd.getColumnName(i));
System.out.print("\t");
System.out.print(rsmd.getColumnTypeName(i));
System.out.print("(");
System.out.print(rsmd.getPrecision(i));
System.out.println(")");
}
} catch (SQLException sqle) {
System.out.println("Erro de SQL: " + sqle);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ignore) {
// Nada a fazer.
}
}
}
}

19

Java e Banco de Dados JDBC On-Line

Captulo 4 Usando Queries PrCompiladas

Provavelmente o maior ponto fraco da interface Statement a necessidade de se fazer as


concatenaes entre as partes estticas da query e os dados reais a serem utilizados. Isso leva
ainda possibilidade de injeo de SQL, constante fonte de preocupao para projetistas e
engenheiros de segurana em aplicaes cliente-servidor.
Para resolver estes problemas, oferecendo ainda uma enorme vantagem em desempenho em
caso de queries executadas em massa, surge a interface PreparedStatement.

A Interface PreparedStatement
Objetos do tipo java.sql.PreparedStatement so obtidos ao se chamar o mtodo
prepareStatement(String sql) do objeto Connection.
Objetos deste tipo so usados para se executar comandos SQL pr-compilados, o que os tornam
especialmente eficientes quando executados mltiplas vezes. Os diferentes mtodos set()
podem ser usados para popular os parmetros da PreparedStatement depois da
compilao da query, possibilitando tornar cada execuo nica.
Mtodo

Descrio

void clearParameters()

Limpa os parmetros imediatamente.

ResultSet executeQuery()

Executa o SQL desta PreparedStetement e


retorna o ResultSet resultante.

int executeUpdate()

Executa o SQL desta PreparedStatement (que


pode ser um INSERT, UPDATE ou DELETE,
ou mesmo um comando DDL) e retorna o
nmero de registros afetados (ou 0 se o
comando no afetou nenhum registro).

ResultSetMetaData getMetaData()

Recupera um objeto ResultSetMetaData que


contm informaes sobre as colunas que
sero
retornadas
quando
esta
PreparedStatement for executada.

ParameterMetaData getParameterMetaData()

Retorna um objeto ParameterMetaData que


contm informao sobre os parmetros desta
PreparedStatement.

void
setBigDecimal(int
BigDecimal x)

parameterIndex, Atribui o valor indicado ao parmetro de


ndice especificado.
20

Java e Banco de Dados JDBC On-Line

Mtodo

Descrio

void setBlob(int parameterIndex, Blob x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setBoolean(int parameterIndex, boolean Atribui o valor indicado ao parmetro de


x)
ndice especificado.
void setByte(int parameterIndex, byte x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setDate(int parameterIndex, Date x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setDouble(int parameterIndex, double x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setFloat(int parameterIndex, float x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setInt(int parameterIndex, int x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setLong(int parameterIndex, long x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setObject(int parameterIndex, Object x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setShort(int parameterIndex, short x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setString(int parameterIndex, String x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void
setTimestamp(int
Timestamp x)

parameterIndex, Atribui o valor indicado ao parmetro de


ndice especificado.

FazendoOutroInsert.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class FazendoOutroInsert {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
return;
}
Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost/agendatelefonica",
"agenda", "agenda");
PreparedStatement ps = con.
prepareStatement("insert into pessoa "
21

Java e Banco de Dados JDBC On-Line

+ "(nome, ddd, telefone) values (?, ?, ?)");


ps.setString(1, "Maria da Graa Santos");
ps.setString(2, "51");
ps.setString(3, "3013-1313");
int incluidos = ps.executeUpdate();
} catch (SQLException sqle) {
System.out.println("Erro de SQL: " + sqle);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ignore) {
// Nada a fazer.
}
}
}
}

22

Java e Banco de Dados JDBC On-Line

Captulo 5 Usando Chaves de AutoIncremento

Quando voc utiliza uma chave de auto-incremento em um banco de dados, no precisa


informar o valor do campo ao efetuar uma incluso. Entretanto, pode ser que voc precise saber
o id gerado para que possa fazer as inseres dos detalhes (ao inserir os dependentes de um
funcionrio, por exemplo, voc precisa saber o ID do funcionrio).
Para que possamos recuperar os valores gerados automaticamente para as chaves de autoincremento precisamos fazer uso de um objeto ResultSet populado pelo banco quando
efetuamos a insero. Este objeto, no entanto, s criado se solicitado no momento em que
executamos o objeto Statement ou obtemos o objeto PreparedStatement:
Statement stmt = con.createStatement();
int afetados = stmt.executeUpdate(<query>,
Statement.RETURN_GENERATED_KEYS);
PreparedStatement ps = com.prepareStatement(<query>,
Statement.RETURN_GENERATED_KEYS);
BuscandoAsChavesGeradas.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class BuscandoAsChavesGeradas {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
return;
}
Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost/agendatelefonica",
"agenda", "agenda");
PreparedStatement ps = con.prepareStatement(
"insert into pessoa (nome, ddd, telefone)"
+ "values (?, ?, ?)",
23

Java e Banco de Dados JDBC On-Line

Statement.RETURN_GENERATED_KEYS);
ps.setString(1, "Mariana Ferreira");
ps.setString(2, "51");
ps.setString(3, "3030-2020");
int registrosIncluidos = ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
rs.next();
int idGerado = rs.getInt("GENERATED_KEY");
System.out.println("O ID gerado foi " + idGerado);
} catch (SQLException sqle) {
System.out.println("Erro de SQL: " + sqle);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ignore) {
// Nada a fazer.
}
}
}
}

24

Java e Banco de Dados JDBC On-Line

Captulo 6 Utilizando Stored


Procedures

A API JDBC, por meio da interface CallableStatement, oferece um recurso simples de


usar para executar e obter os resultados a partir de procedimentos armazenados no banco de
dados (os stored procedures).

A Interface CallableStatement
Objetos do tipo java.sql.CallableStatement so obtidos ao se chamar o mtodo
prepareCall(String sql) do objeto Connection.
Objetos deste tipo so usados para se executar stored procedures no banco. Um stored
procedure pode retornar nenhum, um ou muitos ResultSets. Mltiplos ResultSets so
tratados atravs dos mtodos getResultSet() e getMoreResults().
A API oferece uma sintaxe que permite que stored procedures sejam chamados de uma maneira
consistente, independentemente da plataforma de banco de dados subjacente. H uma sintaxe
para stored procedures que retornam valores e outra para aquelas que no retornam:

{?=
call
<nome-da-stored-procedure>[(<arg1>,
<arg2>,
...)]}
{call <nome-da-stored-procedure>[(<arg1>, <arg2>, ...)]}

Parmetros de entrada devem ser setados usando os mtodos herdados de


PreparedStatement. Parmetros de sada devem ser registrados antes de que o stored
procedure seja chamado.
Mtodo

Descrio

boolean execute()

Executa o Stored Procedure e retorna um


booleano que indica se a chamada foi bemsucedida ou no.

BigDecimal
parameterIndex)

getBigDecimal(int Recupera o valor do parmetro de ndice


indicado.

Blob getBlob(int parameterIndex)

Recupera o valor do parmetro de ndice


indicado.

boolean getBoolean(int parameterIndex)

Recupera o valor do parmetro de ndice


indicado.

byte getByte(int parameterIndex)

Recupera o valor do parmetro de ndice


indicado.
25

Java e Banco de Dados JDBC On-Line

Mtodo

Descrio

Date getDate(int parameterIndex)

Recupera o valor do parmetro de ndice


indicado.

double getDouble(int parameterIndex)

Recupera o valor do parmetro de ndice


indicado.

float getFloat(int parameterIndex)

Recupera o valor do parmetro de ndice


indicado.

int getInt(int parameterIndex)

Recupera o valor do parmetro de ndice


indicado.

long getLong(int parameterIndex)

Recupera o valor do parmetro de ndice


indicado.

Boolean getMoreResults()

Obtm o prximo grupo de resultados deste


CallableStatement e retorna True se ele um
ResultSet.

Object getObject(int parameterIndex)

Recupera o valor do parmetro de ndice


indicado.

ResultSet getResultSet()

Recupera o ResultSet atual.

short getShort(int parameterIndex)

Recupera o valor do parmetro de ndice


indicado.

String getString(int parameterIndex)

String getString(int parameterIndex)

Timestamp
parameterIndex)

getTimestamp(int Recupera o valor do parmetro de ndice


indicado.

void
registerOutParameter(int Registra o parmetro de sada de ndice
parameterIndex, int sqlType)
indicado com o tipo de dados SQL
especificado,
conforme
a
classe
java.sql.Types.
void
setBigDecimal(int
BigDecimal x)

parameterIndex, Atribui o valor indicado ao parmetro de


ndice especificado.

void setBlob(int parameterIndex, Blob x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setBoolean(int parameterIndex, boolean Atribui o valor indicado ao parmetro de


x)
ndice especificado.
void setByte(int parameterIndex, byte x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setDate(int parameterIndex, Date x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setDouble(int parameterIndex, double x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setFloat(int parameterIndex, float x)

Atribui o valor indicado ao parmetro de


ndice especificado.

26

Java e Banco de Dados JDBC On-Line

Mtodo

Descrio

void setInt(int parameterIndex, int x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setLong(int parameterIndex, long x)

Atribui o valor indicado ao parmetro de


ndice especificado.

voud setObject(int parameterIndex, Object x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setString(int parameterIndex, String x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void setShort(int parameterIndex, short x)

Atribui o valor indicado ao parmetro de


ndice especificado.

void
setTimestamp(int
Timestamp x)

parameterIndex, Atribui o valor indicado ao parmetro de


ndice especificado.

Um Stored Procedure Que Retorna um ResultSet


Como primeiro exemplo vamos criar um stored procedure que simplesmente executa uma query
do tipo Select e retorna um ResultSet.
Utilize o cliente de banco de dados de sua preferncia e crie o seguinte stored procedure:
listaPessoas
DELIMITER //
CREATE PROCEDURE listaPessoas()
BEGIN
select * from pessoa;
END;
//
DELIMITER ;
Agora crie a classe Java demonstrada abaixo:
ListaPessoas.java
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ListaPessoas {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
return;
}
Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost/agendatelefonica",
"agenda", "agenda");
CallableStatement cs = con.prepareCall(
27

Java e Banco de Dados JDBC On-Line

"{call listaPessoas()}");
ResultSet rs = cs.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("nome"));
}
} catch (SQLException sqle) {
System.out.println("Erro de SQL: " + sqle);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ignore) {
// Nada a fazer.
}
}
}
}

Um Stored Procedure Que Recebe um Parmetro e Retorna um


ResultSet
Agora vamos tentar melhorar um pouco o nosso procedure, tornando-o um pouco mais flexvel.
Vamos criar uma verso dele que recebe como parmetro um nome de cidade. O procedure,
ento, vai filtrar os registros, retornando apenas aqueles contatos que moram na cidade indicada:
listaPessoasDaCidade
DELIMITER //
CREATE PROCEDURE listaPessoasDaCidade(IN pCidade varchar(40))
BEGIN
select * from pessoa where cidade = pCidade;
END;
//
DELIMITER ;
Note que o procedure indica um parmetro pCidade (do tipo IN, varchar(40)).
Precisaremos passar este parmetro quando chamarmos o procedure.
Agora experimente a classe Java abaixo:
ListaPessoasDaCidade.java
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ListaPessoasDaCidade {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
return;
}
28

Java e Banco de Dados JDBC On-Line

Connection con = null;


try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost/agendatelefonica",
"agenda", "agenda");
CallableStatement cs = con.prepareCall(
"{call listaPessoasDaCidade(?)}");
cs.setString(1, "Porto Alegre");
ResultSet rs = cs.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("nome"));
}
} catch (SQLException sqle) {
System.out.println("Erro de SQL: " + sqle);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ignore) {
// Nada a fazer.
}
}
}
}
Note o uso de cs.setString(1, "Porto Alegre") para definir o valor do parmetro,
exatamente da mesma maneira que faramos com um PreparedStatement. O resto do
cdigo igual ao do exemplo anterior.

Um Stored Procedure Que Retorna um Inteiro


E se quisssemos criar um stored procedure que, ao invs de retornar um ResultSet, retornasse
um dado escalar, como um inteiro por exemplo ?
contaPessoas
DELIMITER //
CREATE FUNCTION contaPessoas()
RETURNS int(11)
BEGIN
declare pessoas integer;
select count(*) into pessoas from pessoa;
return pessoas;
END;
//
DELIMITER ;
Bom, neste caso precisaramos registrar o tipo de dados do retorno. Veja o exemplo:
ContaPessoas.java
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
29

Java e Banco de Dados JDBC On-Line

import java.sql.Types;
public class ContaPessoas {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
return;
}
Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost/agendatelefonica",
"agenda", "agenda");
CallableStatement cs = con.prepareCall(
"{? = call contaPessoas()}");
cs.registerOutParameter(1, Types.INTEGER);
cs.execute();
int pessoas = cs.getInt(1);
System.out.println(pessoas);
} catch (SQLException sqle) {
System.out.println("Erro de SQL: " + sqle);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ignore) {
// Nada a fazer.
}
}
}
}
Repare no uso de cs.registerOutParameter(1, Types.INTEGER), que serve para
indicar a existncia de um parmetro de sada (a primeira interrogao na String que define a
query) do tipo integer. Depois de executarmos a query podemos ler o valor daquele retorno
usando cs.getInt(1).

Um Stored Procedure Que Tem Um Parmetro de Entrada e Sada


Como ltimo exemplo vamos experimentar um stored procedure que tem um parmetro que
serve tanto para entrada como para sada de dados (um parmetro INOUT).
Criaremos uma rotina que, ao receber parte de um nome de um cliente, retorna o primeiro nome
que casa com o critrio de busca. Veja o script abaixo:
buscaPessoa
DELIMITER //
CREATE PROCEDURE buscaPessoa(INOUT pNome varchar(40))
BEGIN
select nome
into pNome
from pessoa
30

Java e Banco de Dados JDBC On-Line

where
order
limit
END;
//
DELIMITER

nome like pNome


by nome
1;
;

Agora veja o cdigo Java que faz uso do stored procedure:


BuscaPessoa.java
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Types;
public class BuscaPessoa {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException cnfe) {
System.out.println("Driver no encontrado.");
return;
}
Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost/agendatelefonica",
"root", "bdr529");
CallableStatement cs = con.prepareCall(
"{call buscaPessoa(?)}");
cs.setString(1, "Mari%");
cs.registerOutParameter(1, Types.VARCHAR);
cs.execute();
String nome = cs.getString(1);
System.out.println("Resultado: " + nome);
} catch (SQLException sqle) {
System.out.println("Erro de SQL: " + sqle);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ignore) {
// Nada a fazer.
}
}
}
}
Desta vez precisamos tanto indicar o valor do parmetro de entrada quanto registrar o parmetro
de sada.
O trecho cs.setString(1, "Mari%") indica o valor do parmetro que ser passado ao
stored procedure. Mas como este um parmetro INOUT (ou seja, o stored procedure tanto
31

Java e Banco de Dados JDBC On-Line

recebe quanto devolve valores por meio deste parmetro), tambm precisamos registr-lo como
um parmetro de sada (com cs.registerOutParameter(1, Types.VARCHAR)).
Note que o nmero 1 em ambos os casos indica ao engine que estamos nos referindo ao
primeiro sinal de interrogao da query.
Depois de executarmos o stored procedure podemos recuperar o valor devolvido pelo mesmo
como se estivssemos lendo dados de um ResultSet (no exemplo, cs.getString(1)).
mvfm, 2012-02-02, Alfamdia

32

Java e Banco de Dados JDBC On-Line

Captulo 7 Usando o Design-Pattern


DAO

Os Objetos de Acesso a Dados (DAO, de Data Access Objects em ingls) constituem uma
parte essencial na arquitetura de uma boa aplicao.
Aplicaes corporativas quase sempre precisam acessar dados a partir de um banco de dados
relacional, e a plataforma Java oferece muitas maneiras de acessar a estes dados. A mais antiga
e mais madura destas tcnicas a API de Java Database Conectivity (JDBC), a qual prov a
capacidade de executar queries SQL em um banco de dados e de recuperar os seus resultados,
uma coluna por vez.
O Design Pattern DAO oferece a flexibilidade de mudar o mecanismo de persistncia de uma
aplicao sem que haja a necessidade de se reprojetar a lgica da aplicao que interage com a
API de persistncia escolhida.
Por exemplo, pode haver benefcios de performance ao se trocar o mecanismo de persistncia de
EJB para chamadas diretas ao JDBC, ou mesmo a mudana para um outro sistema de
persistncia como Spring ou JPA.
Sem uma camada DAO este tipo de transio provocaria enormes modificaes no seu cdigo.
O padro tambm oferece benefcios ao no exigir que seu utilizador conhea todos os
meandros do mecanismo de persistncia escolhido.

33

Java e Banco de Dados JDBC On-Line

No exemplo acima demonstramos uma aplicao em que o acesso ao banco de dados feito
diretamente a partir da lgica de negcio. Esta parece a maneira mais natural de se resolver o
problema, porm ela tem desvantagens importantes. Note que a aplicao envia diretamente
comandos SQL para o driver JDBC, bem como recebe retornos do tipo ResultSet ou
excees do tipo SQLException: se voc trocar a tecnologia de persistncia (por JPA ou EJB,
por exemplo), os tipos de dados certamente sero outros. Modifique a camada de persistncia e
seja obrigado a modificar toda sua lgica de negcio.
O objetivo do design-pattern DAO justamente tornar a substituio do mecanismo de
persistncia transparente do ponto de vista da aplicao.

O que queremos fazer evitar o contato direto entre a lgica de negcios e o engine JDBC.
Fazemos isso por meio do acrscimo de uma camada de intermediria, o nosso componente
DAO. A camada de negcios se comunicar com o DAO por meio de beans (objetos que
representam registros individuais) ou colees de beans ao invs de queries SQL ou
ResultSets, e excees customizadas (que substituem ou encapsulam as SQLExceptions
ou outras excees dependentes da tecnologia de persistncia em uso).
A seguir detalharemos melhor cada um dos componentes da arquitetura proposta.

A Classe de Bean
O bean uma classe Java comum (um POJO, de Plain Old Java Object) que representa uma
entidade na sua aplicao. Tipicamente os beans apresentam uma paridade de 1:1 com as
tabelas do banco de dados (para cada tabela existir um bean). O seu propsito representar um
registro naquela tabela, apresentando mtodos getters e setters e eventuais construtores para
convenincia.
importante que este objeto implemente tambm os mtodos equals() e hashCode(), j
que normalmente ele ser usado em colees. E o mtodo toString() um plus, pois ajuda
bastante no momento do debug.
O estado inicial do bean fica ao seu critrio: alguns preferem ser mais semanticamente precisos
e evitam fornecer valores default para os atributos, j que pode ser que os campos realmente

34

Java e Banco de Dados JDBC On-Line

devam ser null. Outros acham mais conveniente inicializar os atributos com os valores vazios
pertinentes, como demonstrado a seguir.
Pessoa.java
public class Pessoa {
private int id = 0;
private String nome = "";
private String endereco = "";
private String cidade = "";
private String estado = "";
private String cep = "";
private String ddd = "";
private String telefone = "";
public Pessoa() {
}
public Pessoa(int id) {
this.id = id;
}
public Pessoa(String nome) {
this.nome = nome;
}
public Pessoa(int id, String nome) {
this.id = id;
this.nome = nome;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getEndereco() {
return endereco;
}
public void setEndereco(String endereco) {
this.endereco = endereco;
}
public String getCidade() {
return cidade;
}
public void setCidade(String cidade) {
this.cidade = cidade;
}
public String getEstado() {
return estado;
}
public void setEstado(String estado) {
35

Java e Banco de Dados JDBC On-Line

this.estado = estado;
}
public String getCep() {
return cep;
}
public void setCep(String cep) {
this.cep = cep;
}
public String getDdd() {
return ddd;
}
public void setDdd(String ddd) {
this.ddd = ddd;
}
public String getTelefone() {
return telefone;
}
public void setTelefone(String telefone) {
this.telefone = telefone;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Pessoa other = (Pessoa) obj;
if (this.id != other.id) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 31 * hash + this.id;
return hash;
}
@Override
public String toString() {
return "Pessoa{" + "id=" + id + ", nome=" + nome
+ ", endereco=" + endereco + ", cidade="
+ cidade + ", estado=" + estado + ", cep="
+ cep + ", ddd=" + ddd + ", telefone="
+ telefone + '}';
}
}

36

Java e Banco de Dados JDBC On-Line

A Classe DAOException
A classe DAOException ser usada para representar uma exceo customizada que ocorreu
dentro da camada DAO. Ela serve para empacotar instncias de excees dependentes da
camada de persistncia corrente, evitando assim que as classes clientes precisem tomar
conhecimento das mesmas. Se o quiserem, no entanto, podem faz-lo por meio do mtodo
getCause().
DAOException.java
public class DAOException extends Exception {
public DAOException(Throwable cause) {
super(cause);
}
public DAOException(String message, Throwable cause) {
super(message, cause);
}
public DAOException(String message) {
super(message);
}
public DAOException() {
}
}

A Classe DAO
A classe DAO serve como base para a nossa camada de DAO. Ela define os mtodos
getConnection() e closeConnection(), alm das constantes que, de outra forma,
estariam espalhadas pelo cdigo (nome do driver de banco, url do mesmo, usurio, senha ...).
uma classe abstrata, pois nunca a instanciaremos diretamente.
Tambm fica fcil alter-la para se fazer uso de um servio de pool de conexes, por exemplo.
DAO.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public abstract class DAO {
private static final String JDBC_DRIVER =
"com.mysql.jdbc.Driver";
private static final String JDBC_URL =
"jdbc:mysql://localhost/agendatelefonica";
private static final String JDBC_USUARIO = "agenda";
private static final String JDBC_SENHA = "agenda";
private static boolean preparado = false;
public static Connection getConnection()
throws SQLException, DAOException {
if (!preparado) {
try {
Class.forName(JDBC_DRIVER);
preparado = true;
} catch (ClassNotFoundException cnfe) {
System.out.println("Incapaz de carregar o driver "
+ "JDBC: " + cnfe);
37

Java e Banco de Dados JDBC On-Line

throw new DAOException("Incapaz de carregar o "


+ "driver JDBC: " + cnfe, cnfe);
}
}
return DriverManager.getConnection(JDBC_URL,
JDBC_USUARIO, JDBC_SENHA);
}
public static void closeConnection(Connection con) {
if (con != null) {
try {
con.close();
} catch (SQLException sqle) {
// Ignore.
}
}
}
}

A Classe PessoaDAO
A classe concreta de DAO. Para cada tabela no banco teremos uma classe DAO
correspondente. Esta classe ser a responsvel por desempenhar todas as operaes de banco
com esta entidade, ento ela tipicamente declarar mtodos como incluir(), alterar() e
excluir(), alm dos mtodos de pesquisa que se mostrarem necessrios.
PessoaDAO.java
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class PessoaDAO extends DAO {
private static final String SQL_INCLUIR = "insert into "
+ "pessoa (nome, endereco, cidade, estado, cep, "
+ "ddd, telefone) values (?, ?, ?, ?, ?, ?, ?)";
private static final String SQL_ALTERAR = "update pessoa "
+ "set nome = ?, endereco = ?, cidade = ?, "
+ "estado = ?, cep = ?, ddd = ?, telefone = ? "
+ "where id = ?";
private static final String SQL_EXCLUIR = "delete from "
+ "pessoa where idx = ?";
private static final String SQL_BUSCAR_TODOS = "select "
+ "id, nome, endereco, cidade, estado, cep, ddd, "
+ "telefone from pessoa order by nome";
private static final String SQL_BUSCAR_POR_NOME = "select "
+ "id, nome, endereco, cidade, estado, cep, ddd, "
+ "telefone from pessoa where nome like ? order "
+ "by nome";
public static final String SQL_BUSCAR_POR_ID = "select "
+ "id, nome, endereco, cidade, estado, cep, ddd, "
+ "telefone from pessoa where id = ?";
38

Java e Banco de Dados JDBC On-Line

private static final int QUERY_SEM_ID = 0;


private static final int QUERY_COM_ID = 1;
private static final int QUERY_SO_COM_ID = 2;
private static final int QUERY_SO_COM_NOME = 3;
public void incluir(final Pessoa pessoa)
throws DAOException {
Connection con = null;
try {
con = getConnection();
PreparedStatement ps = con.prepareStatement(
SQL_INCLUIR,
Statement.RETURN_GENERATED_KEYS);
populaQuery(ps, pessoa, QUERY_SEM_ID);
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
pessoa.setId(rs.getInt(1));
}
} catch (SQLException sqle) {
System.out.println("Erro de SQL em "
+ "PessoaDAO.incluir(): " + sqle);
throw new DAOException("Erro de SQL em "
+ "PessoaDAO.incluir: " + sqle, sqle);
} finally {
closeConnection(con);
}
}
public void alterar(Pessoa pessoa) throws DAOException {
Connection con = null;
try {
con = getConnection();
PreparedStatement ps = con.prepareStatement(
SQL_ALTERAR);
populaQuery(ps, pessoa, QUERY_COM_ID);
ps.executeUpdate();
} catch (SQLException sqle) {
System.out.println("Erro de SQL em "
+ "PessoaDAO.alterar: " + sqle);
throw new DAOException("Erro de SQL em "
+ "PessoaDAO.alterar: " + sqle, sqle);
} finally {
closeConnection(con);
}
}
public void excluir(Pessoa pessoa) throws DAOException {
Connection con = null;
try {
con = getConnection();
PreparedStatement ps = con.prepareStatement(
SQL_EXCLUIR);
populaQuery(ps, pessoa, QUERY_SO_COM_ID);
int registrosExcluidos = ps.executeUpdate();
if (registrosExcluidos == 0) {
39

Java e Banco de Dados JDBC On-Line

throw new DAOException("Incapaz de excluir o "


+ "registro indicado: o registro no foi "
+ "encontrado.");
}
} catch (SQLException sqle) {
System.out.println("Erro de SQL
+ "PessoaDAO.excluir: "
throw new DAOException("Erro de
+ "PessoaDAO.excluir: "
} finally {
closeConnection(con);
}

em "
+ sqle);
SQL em "
+ sqle, sqle);

}
public List<Pessoa> buscarTodas() throws DAOException {
List<Pessoa> pessoas = new ArrayList();
Connection con = null;
try {
con = getConnection();
PreparedStatement ps = con.prepareStatement(
SQL_BUSCAR_TODOS);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
pessoas.add(lePessoa(rs));
}
} catch (SQLException sqle) {
System.out.println("Erro de SQL em "
+ "PessoaDAO.buscarTodos: " + sqle);
throw new DAOException("Erro de SQL em "
+ "PessoaDAO.buscarTodos: " + sqle, sqle);
} finally {
closeConnection(con);
}
return pessoas;
}
public List<Pessoa> buscarPorNome(Pessoa criterio)
throws DAOException {
List<Pessoa> pessoas = new ArrayList();
Connection con = null;
try {
con = getConnection();
PreparedStatement ps = con.prepareStatement(
SQL_BUSCAR_POR_NOME);
populaQuery(ps, criterio, QUERY_SO_COM_NOME);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
pessoas.add(lePessoa(rs));
}
} catch (SQLException sqle) {
System.out.println("Erro de SQL em "
+ "PessoaDAO.buscarPorNome: " + sqle);
throw new DAOException("Erro de SQL em "
+ "PessoaDAO.buscarPorNome: " + sqle, sqle);
} finally {
40

Java e Banco de Dados JDBC On-Line

closeConnection(con);
}
return pessoas;
}
public Pessoa buscarPorId(Pessoa criterio)
throws DAOException {
Connection con = null;
try {
con = getConnection();
PreparedStatement ps = con.prepareStatement(
SQL_BUSCAR_POR_ID);
populaQuery(ps, criterio, QUERY_SO_COM_ID);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
return lePessoa(rs);
} else {
throw new DAOException("O registro com ID "
+ criterio.getId()
+ " no foi encontrado.");
}
} catch (SQLException sqle) {
System.out.println("Erro de SQL em "
+ "PessoaDAO.buscarPorNome: " + sqle);
throw new DAOException("Erro de SQL em "
+ "PessoaDAO.buscarPorNome: " + sqle, sqle);
} finally {
closeConnection(con);
}
}
private static void populaQuery(PreparedStatement ps,
Pessoa pessoa, int tipoDeQuery)
throws SQLException {
if (tipoDeQuery == QUERY_COM_ID
|| tipoDeQuery == QUERY_SEM_ID) {
ps.setString(1, pessoa.getNome());
ps.setString(2, pessoa.getEndereco());
ps.setString(3, pessoa.getCidade());
ps.setString(4, pessoa.getEstado());
ps.setString(5, pessoa.getCep());
ps.setString(6, pessoa.getDdd());
ps.setString(7, pessoa.getTelefone());
}
if (tipoDeQuery == QUERY_COM_ID) {
ps.setInt(8, pessoa.getId());
} else if (tipoDeQuery == QUERY_SO_COM_ID) {
ps.setInt(1, pessoa.getId());
} else if (tipoDeQuery == QUERY_SO_COM_NOME) {
ps.setString(1, "%" + pessoa.getNome() + "%");
}
}
private static Pessoa lePessoa(ResultSet rs)
throws SQLException {
Pessoa pessoa = new Pessoa();
41

Java e Banco de Dados JDBC On-Line

pessoa.setId(rs.getInt("id"));
pessoa.setNome(rs.getString("nome"));
pessoa.setEndereco(rs.getString("endereco"));
pessoa.setCidade(rs.getString("cidade"));
pessoa.setEstado(rs.getString("estado"));
pessoa.setCep(rs.getString("cep"));
pessoa.setDdd(rs.getString("ddd"));
pessoa.setTelefone(rs.getString("telefone"));
return pessoa;
}
}

42

Você também pode gostar