29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

download 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

of 42

Transcript of 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    1/42

     

    Java e Banco de Dados  –  JDBC

    On-Line

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    2/42

    Java e Banco de Dados  – JDBC  – On-Line

    2

    Todos os direitos reservados para Alfamídia Prow

    AVISO DE RESPONSABILIDADE

    As informações contidas neste material de treinamento são distribuídas “NO ESTADO

    EM QUE SE ENCONTRAM”, sem qualquer garantia, expressa ou implícita. Embora

    todas as precauções tenham sido tomadas na preparação deste material, a AlfamídiaProw não tem qualquer responsabilidade sobre qualquer pessoa ou entidade comrespeito à responsabilidade, perda ou danos causados, ou alegadamente causados, diretaou indiretamente, pelas instruções contidas neste material ou pelo software decomputador e produtos de hardware aqui descritos.

    01/2012 –  Versão 1.0.68

    Alfamídia Prowhttp://www.alfamidia.com.br

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    3/42

    Java e Banco de Dados  – JDBC  – On-Line

    3

    Sumário

    Capítulo 1 –  O Básico ........................................................................................ 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 

    Capítulo 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 

    Capítulo 3 –  Usando Queries Simples ............................................................. 14 

    A Interface Statement .............................................................................................................. 14 

    A Interface ResultSet .............................................................................................................. 15 

    A Interface ResultSetMetaData ............................................................................................... 18 

    Capítulo 4 –  Usando Queries Pré-Compiladas ................................................ 20 

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

    Capítulo 5 –  Usando Chaves de Auto-Incremento........................................... 23 

    Capítulo 6 –  Utilizando Stored Procedures ...................................................... 25 A Interface CallableStatement ................................................................................................ 25 

    Um Stored Procedure Que Retorna um ResultSet ............................................................... 27 

    Um Stored Procedure Que Recebe um Parâmetro e Retorna um ResultSet ........................ 28 

    Um Stored Procedure Que Retorna um Inteiro ................................................................... 29 

    Um Stored Procedure Que Tem Um Parâmetro de Entrada e Saída ................................... 30 

    Capítulo 7 –  Usando o Design-Pattern DAO ................................................... 33 A Classe de Bean .................................................................................................................... 34 

    A Classe DAOException ......................................................................................................... 37 

    A Classe DAO ......................................................................................................................... 37 

    A Classe PessoaDAO .............................................................................................................. 38 

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    4/42

    Java e Banco de Dados  – JDBC  – On-Line

    4

    Capítulo 1 –

     O Básico

    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 lançada 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 dadosrelacional, na época era oferecida apenas uma implementação de referência da Bridge ODBC-JDBC, o que permitia que programas escritos em Java acessassem qualquer fonte de dadosODBC ao alcance do ambiente hospedeiro da JVM.

    JDBC permite que múltiplas implementações coexistam e possam ser usadas na mesmaaplicação. A API provê um mecanismo para carregar dinamicamente os pacotes Javanecessários à conexão com um determinado banco de dados e para registrar estes pacotes frenteà classe DriverManager, que é usada como Factory para se obter as conexões com os mesmos.

    As instruções suportadas incluem CREATE, INSERT, UPDATE, DELETE e SELECT. Háinclusive a possibilidade de se chamarem Stored Procedures.

    Criando Um Banco de Dados de ExemploPara 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 comqualquer outro banco relacional.

    Usando as suas ferramentas de banco de dados preferidas, crie um novo banco de dadoschamado AgendaTelefonica. Lá dentro crie uma tabela chamada Pessoa. Se quiser, crieainda um usuário chamado agenda com senha agenda e lhe dê plenos poderes.

    Você pode o script abaixo como exemplo:CREATE DATABASE AgendaTelefonica CHARACTER SET=latin1COLLATE=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);

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    5/42

    Java e Banco de Dados  – JDBC  – On-Line

    5

    CREATE USER agenda@localhost IDENTIFIED BY 'agenda';GRANT ALL ON *.* TO agenda@localhost;

    Drivers JDBCOs Drivers JDBC são adaptadores instalados no lado cliente que convertem as requisições feitas por meio da API JDBC para um protocolo capaz de ser entendido pelo banco de dados dedestino.

    Existem drivers comerciais e gratuitos para os mais diversos formatos de bancos de dados.Cada um destes drivers cai em uma das quatro categorias disponíveis:

      Tipo 1  Tipo 2  Tipo 3

      Tipo 4Tipo Nome Java Puro Protocolo de Rede Descrição

    Tipo 1 Bridge JDBC-ODBC

     Não Direto Chama código nativode um banco ODBCdisponível localmente

    Tipo 2 API Nativa Não Direto Chama código nativodo fornecedor do banco. Este códigoentão fala com o banco por meio da rede.

    Tipo 3 JDBC –  Net Sim Requer Conector Código Java puro quefala com o middlewaredo banco e então como banco.

    Tipo 4 Direto Sim Direto Driver em Java puroque usa o protocolonativo do banco.

    Instalando o Driver no seu Projeto

    Para que você possa desenvolver uma aplicação que utiliza JDBC você precisará encontrar e

     baixar o driver específico para o seu banco de dados. Em virtualmente todos os casos os driversestarão disponíveis 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 estejadisponível para o compilador e o run-time do Java. Nas páginas 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.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    6/42

    Java e Banco de Dados  – JDBC  – On-Line

    6

    Conector/J é o nome comercial do driver JDBC do MySQL. Clique em DOWNLOAD para baixá-lo.

    Quando a próxima página surgir, escolha o formato que lhe é mais conveniente (tipicamente,usuários do Windows escolherão o formato .zip, enquanto que usuários do Linux escolherão oformato .tar).

    Salve o arquivo em um diretório do seu disco rígido, por exemplo, e depois, usando o WindowsExplorer, navegue até aquele local.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    7/42

    Java e Banco de Dados  – JDBC  – On-Line

    7

    Abra o arquivo que você baixou com um descompactador de sua preferência.

    Lá dentro você encontrará um arquivo mysql-connector-java--bin.jar.Extraia-o para um diretório de sua preferência. Este é o único arquivo de que precisamos, masse você quiser pode extrair todo o conteúdo do arquivo .zip para algum diretório e explorá-lo.O diretório docs, por exemplo, está cheio de documentação e exemplos de código que são bastante úteis.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    8/42

    Java e Banco de Dados  – JDBC  – On-Line

    8

    O arquivo .jar que extraímos é o arquivo que contém as classes Java que são necessárias paraconectar a um banco de dados MySQL. Com o arquivo salvo em algum lugar, agora é hora deacrescentá-lo ao seu projeto. Nas imagens abaixo mostraremos o processo usando o NetBeans,nas o processo não é muito diferente se você estiver usando outro IDE, como o Eclipse porexemplo.

    Depois de abrir o NetBeans e criar o seu projeto, clique com o botão direito sobre ele no ProjectExplorer e selecione a opção Propriedades. Com a janela Propriedades do projeto aberta, clique em Bibliotecas. Você verá algo parecido com a tela mostrada abaixo.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    9/42

    Java e Banco de Dados  – JDBC  – On-Line

    9

    Agora clique no botão Adicionar JAR/pasta para que possa selecionar o arquivo .jar que extraímos.

     Navegue até o diretório onde você salvou o arquivo .jar e selecione-o, clicando em Abrir em seguida.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    10/42

    Java e Banco de Dados  – JDBC  – On-Line

    10

    Pronto, a biblioteca JDBC do MySQL está agora disponível em seu projeto.

    A Rotina de Uso da API JDBCAs classes da API JDBC estão no pacote java.sql. Além dessas você vai precisar dasclasses que implementam o driver para o seu banco de dados específico (a não ser que estejausando a Bridge JDBC-ODBC).

    Os drivers precisam se registrar com a classe DriverManager para que possamos nos utilizardos seus serviços. A partir do JDBC 4.0 (Java 6) esta operação é feita automaticamente, bastando que um driver compatível esteja no CLASSPATH.

    DriverManager é a classe que identifica qual o melhor driver a utilizar para se conectar comum determinado banco de dados.

    Uma aplicação JDBC típica desempenhará as seguintes operações quando consultando dados no banco:

      Registrará o driver junto ao DriverManager;  Obterá uma conexão 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 desconexão.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    11/42

    Java e Banco de Dados  – JDBC  – On-Line

    11

    Capítulo 2 –

     Preparando para Usar oBanco de Dados

     Neste capítulo veremos um pouco do que é necessário para que possamos criar aplicações queutilizem a API JDBC.

    Registrando um Driver JDBC

    A Classe DriverManager

    Como dito anteriormente, é a classe java.sql.DriverManager que sabe qual o driver quemelhor atende a um determinado tipo de banco de dados. Quando os drivers se registram frenteao DriverManager eles informam o seu tipo e a que banco são capazes de atender.

    Isto possibilita que, quando solicitamos uma conexão, não precisemos informar o driver autilizar: basta indicar a URL do banco e o

    DriverManager faz o resto por nós.

    try {Class.forName("");

    } catch (ClassNotFoundException cnfe) {System.out.println("Driver não encontrado.");

    }

     No exemplo acima,  é o nome completamente qualificado da classeque implementa o driver para o seu banco específico. No caso do MySQL este driver se chamacom.mysql.jdbc.Driver. Outros bancos, obviamente, terão classes diferentes.

    Se esta classe porventura não for encontrada no classpath da aplicação umaClassNotFoundException  será lançada. Você poderá capturar esta exceção para

    informar ao usuário do ocorrido, ou para armazenar esta informação no log. Obviamente, seeste erro ocorrer nenhum código 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 não encontrado.");

    }}

    }

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    12/42

    Java e Banco de Dados  – JDBC  – On-Line

    12

    Carga Automática do Driver JDBC

    A partir da versão 4.0 da API JDBC (incluída a partir do Java SE 6) não precisamos mais incluir

    explicitamente o driver do banco. O DriverManager terá a responsabilidade de procurar emtodos os JARs da aplicação por drivers JDBC. O arquivo JAR de um Driver JDBC deve possuiro arquivo META-INF/services/java.sql.Driver, o qual indicará o nome da classeJava que implementa o Driver JDBC.

    Conectando a um Banco de Dados

    A Interface Connection

    A interface java.sql.Connection  representa uma conexão (uma sessão) frente a um banco de dados: comandos SQL e resultados são retornados dentro do contexto de uma

    conexão.Obtém-se um objeto do tipo Connection ao se chamar o método getConnection() daclasse abstrata DriverManager, passando como argumentos a URL do banco de dados à qualse deseja conectar, o nome e a senha de um usuário com autorização para acessá-lo.

    Um objeto do tipo Connection é capaz de obter informações a respeito do banco ao qual estáconectado, como por exemplo:

      A gramática suportada;  Suas tabelas;  Seus stored procedures;  Etc.

    try {Connection con = DriverManager.getConnection(

    “”, “”, “”); } catch (SQLException sqle) {

    System.out.println(“Incapaz de conectar.”); 

    }

     No exemplo acima,   é a URL de conexão com o banco de dados; já os atributos  e   representam o par nome de usuário e senha, e oferecem ascredenciais para acesso ao servidor de banco de dados.

    A tabela abaixo apresenta os métodos mais importantes definidos pela interface

    java.sql.Connection:Método Descrição

    void close() Encerra esta conexão.

    void commit() Persiste todas as mudanças feitas desde oúltimo commit ou rollback.

    Statement createStatement() Cria um objeto do tipo Statement para enviarcomandos ao banco de dados.

     boolean isClosed() Identifica se esta conexão está fechada ou não.Se a conexão estiver fechada não

    conseguiremos executar qualquer query ououtra operação de banco.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    13/42

    Java e Banco de Dados  – JDBC  – On-Line

    13

    Método Descrição

     boolean isReadOnly() Identifica se esta conexão é de apenas leituraou não.

     boolean isValid() Identifica se esta conexão está efetivamenteconectada a um banco de dados e se continuaválida.

    CallableStatement prepareCall(String sql) Cria um objeto do tipo CallableStatement parachamar stored procedures do banco.

    PreparedStatement prepareStatement(Stringsql)

    Cria um objeto do tipo PreparedStatement para enviar comandos SQL pré-compilados para o banco de dados.

    void rollback() Desfaz todas as mudanças 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 não encontrado.");return;}Connection con = null;try {

    con = DriverManager.getConnection("jdbc:mysql://localhost/agendatelefonica","agenda", "agenda");

    // Você colocaria aqui o código 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.}

    }}

    }

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    14/42

    Java e Banco de Dados  – JDBC  – On-Line

    14

    Capítulo 3 –

     Usando Queries Simples

    Java oferece três interfaces principais para enviar comandos ao banco de dados:

      Statement

      PreparedStatement  CallableStatement

    Instâncias delas são obtidas através de chamadas a métodos específicos do objeto Connectionutilizado para conectar ao banco de dados.

     Neste capítulo veremos a mais simples delas, Statement, mas nos próximos capítulosfalaremos de PreparedStatement e CallableStatement.

    A Interface StatementObjetos do tipo java.sql.Statement  são criados ao se chamar o método

    createStatement() do objeto Connection.Objetos deste tipo são usados para executar comandos SQL estáticos e obter os resultados queeles produzem, seja por meio de valores primitivos ou por meio de um objetojava.sql.ResultSet  (primitivos são retornados quando o comando em questão apenasinforma o sucesso ou o número de registros afetados; um ResultSet é retornado quando umaquery retorna o grupo de registros selecionados pelo seu critério de filtro).

    Os métodos abaixo podem ser utilizados:

    Método Descrição

    void close() Encerra esta Statement.

    ResultSet executeQuery(String sql) Executa o SQL indicado e retorna o ResultSetresultante.

    int executeUpdate(String sql) Executa o SQL indicado (que pode ser umINSERT, UPDATE ou DELETE, ou mesmoum comando DDL) e retorna o número deregistros afetados (ou 0 se o comando nãoafetou nenhum registro).

    ResultSet getGeneratedKeys() Retorna um ResultSet que indica as chavesgeradas ao se executar a Statement.

     boolean isClosed() Indica se esta Stetement está fechada ou não.

    FazendoUmInsert.javaimport java.sql.Connection;

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    15/42

    Java e Banco de Dados  – JDBC  – On-Line

    15

    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 não 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 ('João 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 ResultSetUm ResultSet  agrega os dados recuperados a partir do banco de dados em uma estrutura

    semelhante a um iterator de uma coleção. Ele é geralmente obtido por meio de instruções queconsultam o banco, como as Statement  e PreparedStatement, mas também pode serretornado por instâncias 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  são navegáveis apenas para a frente e não são atualizáveis.Métodos factory especiais em Connection  permitem que ResultSet  navegáveis eatualizáveis sejam criados, mas eles normalmente consumem muito mais recursos do banco enão são muito utilizados.

    Apenas um ResultSet pode estar aberto por cada Statement, PreparedStatement ou

    CallableStatement, então múltiplos objetos serão necessários no caso de se fazeremconsultas encadeadas.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    16/42

    Java e Banco de Dados  – JDBC  – On-Line

    16

    Um ResultSet  é automaticamente fechado quando o objeto Statement,PreparedStatement ou CallableStatement que o gerou é fechado, re-executado ou

    usado para recuperar o próximo resultado dentro de uma sequência de múltiplos resultados.A tabela a seguir mostra alguns dos métodos mais importantes da interface ResultSet.

    Método Descrição

    int findColumn(String columnLabel) Retorna o índice da coluna indicada.

    BigDecimal getBigDecimal(int parameterIndex)

    Recupera o valor da coluna de índiceindicado.

    Blob getBlob(int parameterIndex) Recupera o valor da coluna de índiceindicado.

     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 índiceindicado.

    double getDouble(int parameterIndex) Recupera o valor da coluna de índiceindicado.

    float getFloat(int parameterIndex) Recupera o valor da coluna de índiceindicado.

    int getInt(int parameterIndex) Recupera o valor da coluna de índiceindicado.

    long getLong(int parameterIndex) Recupera o valor da coluna de índiceindicado.

    ResultSetMetaData getMetaData() Retorna um objeto ResultSetMetaData cominformações a respeito das colunas retornadas por este ResultSet,

    Boolean getMoreResults() Obtém o próximo grupo de resultados desteCallableStatement e retorna True se ele é umResultSet.

    Object getObject(int parameterIndex) Recupera o valor da coluna de índiceindicado.

    int getRow() Recupera o número da linha atual.

    short getShort(int parameterIndex) Recupera o valor da coluna de índiceindicado.

    String getString(int parameterIndex) Recupera o valor da coluna de índiceindicado.

    Timestamp getTimestamp(int parameterIndex)

    Recupera o valor da coluna de índiceindicado.

     boolean isAfterLast() Indica se o cursor está posicionado além daúltima linha recuperada por este ResultSet.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    17/42

    Java e Banco de Dados  – JDBC  – On-Line

    17

    Método Descrição

     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 últimalinha recuperada por este ResultSet.

     boolean next() Move o cursor uma linha para frente e retornaTrue se ainda não ultrapassou o final da listade 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 não 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.}

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    18/42

    Java e Banco de Dados  – JDBC  – On-Line

    18

    }}

    }

    A Interface ResultSetMetaDataPor meio da interface ResultSetMetaData pode-se descobrir a quantidade e tipo de dadosde cada coluna que seria/foi retornada por uma query. Com isso poderíamos criar utilitários ou programas que lidam com dados sobre os quais nada se sabe de antemão, exatamente como oPHPMyAdmin ou o Navicat fazem.

    Obtém-se um ResultSetMetaData  ao se chamar o método getMetaData()  de umainstância de PreparedStatement, CallableStatement ou ResultSet.

    A tabela abaixo exibe os métodos mais utilizados em ResultSetMetaData:

    Método Descrição

    String getCatalogName(int column) Retorna o nome do catálogo que armazena atabela à qual a coluna indicada pertence.

    String getColumnClassName(int column) Retorna o nome qualificado da classe Javaque seria usada para retornar a colunaindicada se o método getObject() fossechamado.

    int getColumnCount() Retorna o número de colunas deste objetoResultSet.

    String getColumnLabel(int column) Retorna o label definido para a colunaindicada.

    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 colunaindicada, conforme o banco de dados usado.

    int getPrecision(int column) Retorna o tamanho da coluna indicada. Paracolunas do tipo caractere isto equivale aocomprimento da coluna, enquanto que para

    dados numéricos esta é a parte inteira.int getScale(int column) Retorna o número de casas decimais da

    coluna indicada. Para colunas do tipocaractere o valor será sempre zero.

    String getSchemaName(int column) Retorna o nome do esquema da colunaindicada.

    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;

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    19/42

    Java e Banco de Dados  – JDBC  – On-Line

    19

    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 não 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

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    20/42

    Java e Banco de Dados  – JDBC  – On-Line

    20

    Capítulo 4 –

     Usando Queries Pré-Compiladas

    Provavelmente o maior ponto fraco da interface Statement  é a necessidade de se fazer asconcatenações entre as partes estáticas da query e os dados reais a serem utilizados. Isso levaainda à possibilidade de injeção de SQL, constante fonte de preocupação para projetistas eengenheiros de segurança em aplicações cliente-servidor.

    Para resolver estes problemas, oferecendo ainda uma enorme vantagem em desempenho emcaso de queries executadas em massa, surge a interface PreparedStatement.

    A Interface PreparedStatementObjetos do tipo java.sql.PreparedStatement  são obtidos ao se chamar o métodoprepareStatement(String sql) do objeto Connection.

    Objetos deste tipo são usados para se executar comandos SQL pré-compilados, o que os tornamespecialmente eficientes quando executados múltiplas vezes. Os diferentes métodos set()  podem ser usados para popular os parâmetros da PreparedStatement  depois dacompilação da query, possibilitando tornar cada execução única.

    Método Descrição

    void clearParameters() Limpa os parâmetros imediatamente.

    ResultSet executeQuery() Executa o SQL desta PreparedStetement eretorna 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 onúmero de registros afetados (ou 0 se ocomando não afetou nenhum registro).

    ResultSetMetaData getMetaData() Recupera um objeto ResultSetMetaData quecontém informações sobre as colunas queserão retornadas quando estaPreparedStatement for executada.

    ParameterMetaData getParameterMetaData() Retorna um objeto ParameterMetaData quecontém informação sobre os parâmetros destaPreparedStatement.

    void setBigDecimal(int parameterIndex,BigDecimal x)

    Atribui o valor indicado ao parâmetro deíndice especificado.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    21/42

    Java e Banco de Dados  – JDBC  – On-Line

    21

    Método Descrição

    void setBlob(int parameterIndex, Blob x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setBoolean(int parameterIndex, booleanx)

    Atribui o valor indicado ao parâmetro deíndice especificado.

    void setByte(int parameterIndex, byte x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setDate(int parameterIndex, Date x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setDouble(int parameterIndex, double x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setFloat(int parameterIndex, float x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setInt(int parameterIndex, int x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setLong(int parameterIndex, long x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setObject(int parameterIndex, Object x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setShort(int parameterIndex, short x) Atribui o valor indicado ao parâmetro de

    índice especificado.void setString(int parameterIndex, String x) Atribui o valor indicado ao parâmetro de

    índice especificado.

    void setTimestamp(int parameterIndex,Timestamp x)

    Atribui o valor indicado ao parâmetro 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 não encontrado.");return;

    }Connection con = null;try {

    con = DriverManager.getConnection("jdbc:mysql://localhost/agendatelefonica",

    "agenda", "agenda");PreparedStatement ps = con.prepareStatement("insert into pessoa "

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    22/42

    Java e Banco de Dados  – JDBC  – On-Line

    22

    + "(nome, ddd, telefone) values (?, ?, ?)");ps.setString(1, "Maria da Graça 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.

    }}}

    }

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    23/42

    Java e Banco de Dados  – JDBC  – On-Line

    23

    Capítulo 5 –

     Usando Chaves de Auto-Incremento

    Quando você utiliza uma chave de auto-incremento em um banco de dados, não precisainformar o valor do campo ao efetuar uma inclusão. Entretanto, pode ser que você precise sabero id gerado para que possa fazer as inserções dos detalhes (ao inserir os dependentes de umfuncionário, por exemplo, você precisa saber o ID do funcionário).

    Para que possamos recuperar os valores gerados automaticamente para as chaves de auto-incremento precisamos fazer uso de um objeto ResultSet  populado pelo banco quandoefetuamos a inserção. Este objeto, no entanto, só é criado se solicitado no momento em queexecutamos o objeto Statement ou obtemos o objeto PreparedStatement:Statement stmt = con.createStatement();int afetados = stmt.executeUpdate(“”,

    Statement.RETURN_GENERATED_KEYS);

    PreparedStatement ps = com.prepareStatement(“”,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 não 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 (?, ?, ?)",

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    24/42

    Java e Banco de Dados  – JDBC  – On-Line

    24

    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.}

    }}

    }

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    25/42

    Java e Banco de Dados  – JDBC  – On-Line

    25

    Capítulo 6 –

     Utilizando StoredProcedures

    A API JDBC, por meio da interface CallableStatement, oferece um recurso simples deusar para executar e obter os resultados a partir de procedimentos armazenados no banco dedados (os stored procedures).

    A Interface CallableStatementObjetos do tipo java.sql.CallableStatement  são obtidos ao se chamar o métodoprepareCall(String sql) do objeto Connection.

    Objetos deste tipo são usados para se executar stored procedures no banco. Um stored procedure pode retornar nenhum, um ou muitos ResultSets. Múltiplos ResultSets sãotratados através dos métodos getResultSet() e getMoreResults().

    A API oferece uma sintaxe que permite que stored procedures sejam chamados de uma maneiraconsistente, independentemente da plataforma de banco de dados subjacente. Há uma sintaxe para stored procedures que retornam valores e outra para aquelas que não retornam:

      {?= call [(, ,...)]}

      {call [(, , ...)]}

    Parâmetros de entrada devem ser setados usando os métodos herdados dePreparedStatement. Parâmetros de saída devem ser registrados antes de que o stored procedure seja chamado.

    Método Descrição

     boolean execute() Executa o Stored Procedure e retorna um booleano que indica se a chamada foi bem-sucedida ou não.

    BigDecimal getBigDecimal(int parameterIndex)

    Recupera o valor do parâmetro de índiceindicado.

    Blob getBlob(int parameterIndex) Recupera o valor do parâmetro de índiceindicado.

     boolean getBoolean(int parameterIndex) Recupera o valor do parâmetro de índiceindicado.

     byte getByte(int parameterIndex) Recupera o valor do parâmetro de índiceindicado.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    26/42

    Java e Banco de Dados  – JDBC  – On-Line

    26

    Método Descrição

    Date getDate(int parameterIndex) Recupera o valor do parâmetro de índiceindicado.

    double getDouble(int parameterIndex) Recupera o valor do parâmetro de índiceindicado.

    float getFloat(int parameterIndex) Recupera o valor do parâmetro de índiceindicado.

    int getInt(int parameterIndex) Recupera o valor do parâmetro de índiceindicado.

    long getLong(int parameterIndex) Recupera o valor do parâmetro de índiceindicado.

    Boolean getMoreResults() Obtém o próximo grupo de resultados desteCallableStatement e retorna True se ele é umResultSet.

    Object getObject(int parameterIndex) Recupera o valor do parâmetro de índiceindicado.

    ResultSet getResultSet() Recupera o ResultSet atual.

    short getShort(int parameterIndex) Recupera o valor do parâmetro de índiceindicado.

    String getString(int parameterIndex) String getString(int parameterIndex)

    Timestamp getTimestamp(int parameterIndex)

    Recupera o valor do parâmetro de índiceindicado.

    void registerOutParameter(int parameterIndex, int sqlType)

    Registra o parâmetro de saída de índiceindicado com o tipo de dados SQLespecificado, conforme a classe java.sql.Types.

    void setBigDecimal(int parameterIndex,BigDecimal x)

    Atribui o valor indicado ao parâmetro deíndice especificado.

    void setBlob(int parameterIndex, Blob x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setBoolean(int parameterIndex, booleanx)

    Atribui o valor indicado ao parâmetro deíndice especificado.

    void setByte(int parameterIndex, byte x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setDate(int parameterIndex, Date x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setDouble(int parameterIndex, double x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setFloat(int parameterIndex, float x) Atribui o valor indicado ao parâmetro de

    índice especificado.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    27/42

    Java e Banco de Dados  – JDBC  – On-Line

    27

    Método Descrição

    void setInt(int parameterIndex, int x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setLong(int parameterIndex, long x) Atribui o valor indicado ao parâmetro deíndice especificado.

    voud setObject(int parameterIndex, Object x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setString(int parameterIndex, String x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setShort(int parameterIndex, short x) Atribui o valor indicado ao parâmetro deíndice especificado.

    void setTimestamp(int parameterIndex,Timestamp x)

    Atribui o valor indicado ao parâmetro deíndice especificado.

    Um Stored Procedure Que Retorna um ResultSet

    Como primeiro exemplo vamos criar um stored procedure que simplesmente executa uma querydo tipo Select e retorna um ResultSet.

    Utilize o cliente de banco de dados de sua preferência 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 não encontrado.");return;

    }Connection con = null;try {

    con = DriverManager.getConnection(

    "jdbc:mysql://localhost/agendatelefonica","agenda", "agenda");CallableStatement cs = con.prepareCall(

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    28/42

    Java e Banco de Dados  – JDBC  – On-Line

    28

    "{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 Parâmetro e Retorna umResultSet

    Agora vamos tentar melhorar um pouco o nosso procedure, tornando-o um pouco mais flexível.Vamos criar uma versão dele que recebe como parâmetro um nome de cidade. O procedure,então, 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 parâmetro pCidade  (do tipo IN, varchar(40)).Precisaremos passar este parâmetro quando chamarmos o procedure.

    Agora experimente a classe Java abaixo:

    ListaPessoasDaCidade.javaimport 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 não encontrado.");

    return;}

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    29/42

    Java e Banco de Dados  – JDBC  – On-Line

    29

    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 parâmetro,

    exatamente da mesma maneira que faríamos com um PreparedStatement. O resto docódigo é igual ao do exemplo anterior.

    Um Stored Procedure Que Retorna um Inteiro

    E se quiséssemos criar um stored procedure que, ao invés de retornar um ResultSet, retornasseum 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 precisaríamos 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;

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    30/42

    Java e Banco de Dados  – JDBC  – On-Line

    30

    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 não 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 paraindicar a existência de um parâmetro de saída (a primeira interrogação na String que define aquery) do tipo integer. Depois de executarmos a query podemos ler o valor daquele retornousando cs.getInt(1).

    Um Stored Procedure Que Tem Um Parâmetro de Entrada e Saída

    Como último exemplo vamos experimentar um stored procedure que tem um parâmetro queserve tanto para entrada como para saída de dados (um parâmetro INOUT).

    Criaremos uma rotina que, ao receber parte de um nome de um cliente, retorna o primeiro nomeque casa com o critério de busca. Veja o script abaixo:

     buscaPessoa

    DELIMITER //CREATE PROCEDURE buscaPessoa(INOUT pNome varchar(40))BEGIN

    select nomeinto pNomefrom pessoa

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    31/42

    Java e Banco de Dados  – JDBC  – On-Line

    31

    where nome like pNomeorder by nomelimit 1;

    END;//DELIMITER ;

    Agora veja o código 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 não 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 parâmetro de entrada quanto registrar o parâmetrode saída.

    O trecho cs.setString(1, "Mari%") indica o valor do parâmetro que será passado aostored procedure. Mas como este é um parâmetro INOUT (ou seja, o stored procedure tanto

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    32/42

    Java e Banco de Dados  – JDBC  – On-Line

    32

    recebe quanto devolve valores por meio deste parâmetro), também precisamos registrá-lo comoum parâmetro de saída (com cs.registerOutParameter(1, Types.VARCHAR)).

     Note que o número 1  em ambos os casos indica ao engine que estamos nos referindo ao primeiro sinal de interrogação da query.

    Depois de executarmos o stored procedure podemos recuperar o valor devolvido pelo mesmocomo se estivéssemos lendo dados de um ResultSet (no exemplo, cs.getString(1)).

    mvfm, 2012-02-02, Alfamídia 

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    33/42

    Java e Banco de Dados  – JDBC  – On-Line

    33

    Capítulo 7 –

     Usando o Design-PatternDAO

    Os Objetos de Acesso a Dados (DAO, de “Data Access Objects” em inglês) constituem uma

     parte essencial na arquitetura de uma boa aplicação.

    Aplicações corporativas quase sempre precisam acessar dados a partir de um banco de dadosrelacional, e a plataforma Java oferece muitas maneiras de acessar a estes dados. A mais antigae mais madura destas técnicas é a API de Java Database Conectivity (JDBC), a qual provê acapacidade 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 persistência de umaaplicação sem que haja a necessidade de se reprojetar a lógica da aplicação que interage com aAPI de persistência escolhida.

    Por exemplo, pode haver benefícios de performance ao se trocar o mecanismo de persistência de

    EJB para chamadas diretas ao JDBC, ou mesmo a mudança para um outro sistema de persistência como Spring ou JPA.

    Sem uma camada DAO este tipo de transição provocaria enormes modificações no seu código.

    O padrão também oferece benefícios ao não exigir que seu utilizador conheça todos osmeandros do mecanismo de persistência escolhido.

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    34/42

    Java e Banco de Dados  – JDBC  – On-Line

    34

     No exemplo acima demonstramos uma aplicação em que o acesso ao banco de dados é feitodiretamente a partir da lógica de negócio. Esta parece a maneira mais natural de se resolver o problema, porém ela tem desvantagens importantes. Note que a aplicação envia diretamentecomandos SQL para o driver JDBC, bem como recebe retornos do tipo ResultSet  ouexceões do tipo SQLException: se você trocar a tecnologia de persistência (por JPA ou EJB, por exemplo), os tipos de dados certamente serão outros. Modifique a camada de persistência eseja obrigado a modificar toda sua lógica de negócio.

    O objetivo do design-pattern DAO é justamente tornar a substituição do mecanismo de persistência transparente do ponto de vista da aplicação.

    O que queremos fazer é evitar o contato direto entre a lógica de negócios e o engine JDBC.Fazemos isso por meio do acréscimo de uma camada de intermediária, o nosso componenteDAO. A camada de negócios se comunicará com o DAO por meio de beans (objetos querepresentam registros individuais) ou coleções de beans ao invés de queries SQL ouResultSets, e exceções customizadas (que substituem ou encapsulam as SQLExceptionsou outras exceções dependentes da tecnologia de persistência em uso).

    A seguir detalharemos melhor cada um dos componentes da arquitetura proposta.

    A Classe de BeanO bean é uma classe Java comum (um POJO, de “Plain Old Java Object”) que representa umaentidade na sua aplicação. Tipicamente os beans apresentam uma paridade de 1:1 com astabelas do banco de dados (para cada tabela existirá um bean). O seu propósito é representar umregistro naquela tabela, apresentando métodos getters e setters e eventuais construtores paraconveniência.

    É importante que este objeto implemente também os métodos equals() e hashCode(), jáque normalmente ele será usado em coleções. E o método toString() é um plus, pois ajuda bastante no momento do debug.

    O estado inicial do bean fica ao seu critério: alguns preferem ser mais semanticamente precisos

    e evitam fornecer valores default para os atributos, já que pode ser que os campos realmente

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    35/42

    Java e Banco de Dados  – JDBC  – On-Line

    35

    devam ser null. Outros acham mais conveniente inicializar os atributos com os valores vazios pertinentes, como demonstrado a seguir.

    Pessoa.javapublic 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) {

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    36/42

    Java e Banco de Dados  – JDBC  – On-Line

    36

    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;}@Overridepublic 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;

    }@Overridepublic int hashCode() {

    int hash = 3;hash = 31 * hash + this.id;

    return hash;}@Overridepublic String toString() {

    return "Pessoa{" + "id=" + id + ", nome=" + nome+ ", endereco=" + endereco + ", cidade="+ cidade + ", estado=" + estado + ", cep="+ cep + ", ddd=" + ddd + ", telefone="+ telefone + '}';

    }}

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    37/42

    Java e Banco de Dados  – JDBC  – On-Line

    37

    A Classe DAOException

    A classe DAOException será usada para representar uma exceção customizada que ocorreudentro da camada DAO. Ela serve para empacotar instâncias de exceções dependentes dacamada de persistência corrente, evitando assim que as classes clientes precisem tomarconhecimento das mesmas. Se o quiserem, no entanto, podem fazê-lo por meio do métodogetCause().

    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 DAOA classe DAO serve como base para a nossa camada de DAO. Ela define os métodos

    getConnection()  e closeConnection(), além das constantes que, de outra forma,estariam espalhadas pelo código (nome do driver de banco, url do mesmo, usuário, senha ...). Éuma classe abstrata, pois nunca a instanciaremos diretamente.

    Também fica fácil alterá-la para se fazer uso de um serviço de pool de conexões, 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);

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    38/42

    Java e Banco de Dados  – JDBC  – On-Line

    38

    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 PessoaDAOA classe concreta de DAO. Para cada tabela no banco teremos uma classe DAOcorrespondente. Esta classe será a responsável por desempenhar todas as operações de bancocom esta entidade, então ela tipicamente declarará métodos como incluir(), alterar() eexcluir(), além dos métodos de pesquisa que se mostrarem necessários.

    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 = ?";

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    39/42

    Java e Banco de Dados  – JDBC  – On-Line

    39

    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) {

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    40/42

    Java e Banco de Dados  – JDBC  – On-Line

    40

    throw new DAOException("Incapaz de excluir o "+ "registro indicado: o registro não foi "+ "encontrado.");

    }} catch (SQLException sqle) {

    System.out.println("Erro de SQL em "+ "PessoaDAO.excluir: " + sqle);

    throw new DAOException("Erro de SQL em "+ "PessoaDAO.excluir: " + sqle, sqle);

    } finally {closeConnection(con);

    }}public List buscarTodas() throws DAOException {

    List 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 buscarPorNome(Pessoa criterio)

    throws DAOException {List 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 {

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    41/42

    Java e Banco de Dados  – JDBC  – On-Line

    41

    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()+ " não 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();

  • 8/18/2019 29 Java e Banco de Dados (JDBC) [Versão 1.0.68 2012-01] - Alfamídia

    42/42