Introdução à programação para web com Java - Módulo 01: Conexão com bamco de dados (JDBC)

49
AULA 04 – JDBC

Transcript of Introdução à programação para web com Java - Módulo 01: Conexão com bamco de dados (JDBC)

Page 1: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

AULA 04 – JDBC

Page 2: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A conexão em Java

Objetivos

Page 3: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A conexão em Java

Conectar-se a um banco de dados com Java é feito de maneira elegante. Para evitar que cada banco tenhaa sua própria API e conjunto de classes e métodos, temos um único conjunto de interfaces muito bem definidasque devem ser implementadas. Esse conjunto de interfaces fica dentro do pacote java.sql e nos referiremos a ela como JDBC (Java Database Connectivity ). Essa interface acessar bases de dados não importando quem seja seu fabricante, pois os desenvolvedores de um JDBC provêem a implementação fornecendo o mesmo grupo de funcionalidades ao desenvolvedor do sistema.

Page 4: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A conexão em Java

As seguintes classes estão na API JDBC:

java.sql.Connection – Representa a conexão com o banco de dados. Encapsula os detalhes de como a comunicação com o servidor é realizada.

java.sql.DriverManager – Gerencia os drivers JDBC utilizados pela aplicação. Em conjunto com o endereço e a autenticação, pode fornecer objetos de conexão.

javax.sql.DataSource – Abrange os detalhes (endereço, autenticação) de como a conexão com o banco de dados é obtida. É o mais recente e o preferido método de obtenção de objetos de conexão.

Page 5: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A conexão em Java

java.sql.Statement – Fornece meios ao desenvolvedor para que se possa executar comandos SQL.

java.sql.ResultSet – Representa o resultado de um comando SQL. Estes objetos normalmente são retornados por métodos.

Page 6: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A conexão em Java

java.sql.Statement – Fornece meios ao desenvolvedor para que se possa executar comandos SQL.

java.sql.ResultSet – Representa o resultado de um comando SQL. Estes objetos normalmente são retornados por métodos.

Page 7: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A interface Connection que define métodos para executar uma query (como um insert e select), comitar transação e fechar a conexão, entre outros. Caso queiramos trabalhar com o MySQL, por exemplo, precisamos de classes concretas que implementem essas interfaces do pacote java.sql.

java.sql.DriverManager

Page 8: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

Esse conjunto de classes concretas é quem fará a ponte entre o código cliente que usa a API JDBC e o banco de dados. São essas classes que sabem se comunicar através do protocolo proprietário do banco de dados. Esse conjunto de classes recebe o nome de driver. Todos os principais bancos de dados do mercado possuem drivers JDBC para que você possa utilizá-los com Java.

O nome driver é análogo ao que usamos para impressoras: como é impossível que um sistema operacional saiba conversar com todo tipo de impressora existente, precisamos de um driver que faça o papel de “tradutor” dessa conversa.

java.sql.DriverManager

Page 9: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

java.sql.DriverManager

Page 10: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

Para abrir uma conexão com um banco de dados, precisamos utilizar sempre um driver. A classe DriverManager é a responsável por se comunicar com todos os drivers que você deixou disponível. Para isso,invocamos o método estático getConnection com uma String que indica a qual banco desejamos nos conectar.

Essa String - chamada de String de conexão JDBC - que iremos utilizar para acessar o MySQL tem sempre a seguinte forma:

jdbc:mysql://ip/nome_do_banco

java.sql.DriverManager

Page 11: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

Devemos substituir ip pelo IP da máquina do servidor e nome_do_banco pelo nome do banco de dados a ser utilizado.

Seguindo o exemplo da linha acima e tudo que foi dito até agora, seria possível rodar o exemplo abaixo e receber uma conexão para um banco MySQL, caso ele esteja rodando na mesma máquina:

jdbc:mysql://ip/nome_do_banco

java.sql.DriverManager

Page 12: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

Lista de driversOs drivers podem ser baixados normalmente no site do fabricante do banco de dados. A Sun possui um sistema de busca de drivers em seu site:

http://developers.sun.com/product/jdbc/drivers

Alguns casos, como no Microsoft SQL Server, existem outros grupos que desenvolvem o driver em http://jtds.sourceforge.net . Enquanto isso, você pode achar o driver do MYSQL (chamado de mysql connector) no site

http://www.mysql.org.

java.sql.DriverManager

Page 13: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

java.sql.DriverManager

Utilizando esta classe, o desenvolvedor pode retornar um objeto de conexão que pode ser usado para executar tarefas relativas ao banco de dados. Dois passos são necessários para tal:

Primeiro, o driver JDBC deve estar registrado com DriverManager. Isto pode ser feito utilizando o método Class.forName que carrega a classe do driver para a memória.

Segundo, utilizando o método getConnection, mediante informação de uma URL, assim como a senha e o nome do usuários autenticados no banco de dados. A URL deve seguir a sintaxe requisitada pela implementação do banco de dados.

Page 14: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

java.sql.DriverManager

Abaixo vemos um exemplo de como se obtém uma conexão com um banco de dados MySql. Novamente, a URL e o driver específicos para a implementação são utilizados. Para outros bancos de dados, verifique a documentação fornecida.

String jdbcURL = "jdbc:mysql://localhost:3306/test";String user = “root"; String password = “admin"; Connection conn = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection(jdbcURL, user, password); ...} catch (SQLException e) { // caso ocorra erro de SQL }

Page 15: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

java.sql.DriverManager

Apesar de ser um método válido para a obtenção de um objeto de conexão, necessita que o desenvolvedor faça o rastreamento de alguns detalhes, tais como: o nome da classe do driver, a url necessária para se efetuar a conexão, o nome de usuário e senhas para o acesso ao banco. Estes detalhes são os que mais estão sujeitos a mudanças a cada compilação da aplicação. Além disso, gerenciar a url e o nome do driver no código dificulta a aplicação a trocar a implementação de sua base de dados, se isto vier a ser necessário.

Page 16: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSource

Esta é uma interface definida na API JDBC desde sua versão 2.

Hoje em dia, este é o modo recomendado para que se obtenham objetos de conexão. Recuperar objetos de conexão é uma tarefa bastante direta: simplesmente chame o método getConnection() de uma instância válida desta interface.

Page 17: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSource

Sendo DataSource uma interface, uma instância não pode ser simplesmente criada pelo desenvolvedor utilizando o operador new.

É recomendado que se deixe para o servidor da aplicação que gerencie a criação de objetos DataSource. Com isto permite-se que o servidor adicione algumas funcionalidades, tais como a connection pooling (reserva de conexões) de uma maneira que é transparente tanto para o desenvolvedor, quanto para o usuário final.

Page 18: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceConfigurando o Datasource no Sun Application Server

Cada servidor possui seu próprio procedimento para a configuração e gerenciamento de DataSources.

São três passos para se configurar um DataSource no AppServer:

● Registrar o arquivo JAR contendo o driver JDBC

● Criar o pool de conexões para o banco de dados

● Registrar um DataSource que utilize este pool

Page 19: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceRegistrando o arquivo JAR

O primeiro passo é acessar o console de administração do servidor e disponibilizar o arquivo de conexão com o banco de dados para o Sun Application Server. Para isso, basta copiar o arquivo .jar para a pasta \lib aonde está instalado o servidor. Por exemplo, com o servidor Glassfish instalado em conjunto com o NetBeans 6.0 pode ser encontrado no Windows na pasta:

C:\Program Files\glassfish-v2\

Para acessar as configurações do grassfish digite no browser http://localhost:4848 Entre com o usuário e senhaadmin, adminadmin

Page 20: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceCriando um pool de conexão

Para iniciar a criação de um pool de conexão, selecione Resources | JDBC | Connection Pools no painel a esquerda. Na tela exibida, pressione o botão New e uma tela similar a Figura 2 será mostrada.

Em Name entre com o nome como este pool de conexão será conhecido (exemplo: IFRJPool). Em Resource Type selecione javax.sql.DataSource. No Database Vendor selecione o banco de dados utilizado, caso o banco que esteja utilizando não apareça na lista deixe esta opção em branco.Pressione o botão Next, no campo Datasource Classname, caso não venha preenchido por padrão, informe o nome da classe do seu banco, para o MySql: com.mysql.jdbc.jdbc2.optional.MysqlDataSourcecom.mysql.jdbc2.Jdbc2PoolingDataSource

Page 21: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceCriando um pool de conexão

Observe as propriedades para associar com este pool de conexões. Os parâmetros seguintes necessitam ter seus valores fornecidos:

• Password – Senha do banco de dados• ServerName – Nome do servidor do banco de dados• PortNumber – Número da porta• DatabaseName – Nome do Banco de dados• User – Nome do usuário

Depois de completar os valores, pressione o botão Finish.

Page 22: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceCriando um pool de conexão

Page 23: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceCriando um pool de conexão

Page 24: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceCriando um pool de conexão

Page 25: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceCriando um pool de conexão

User = rootPassword = adminServerName = localhost

Page 26: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceCriando um pool de conexão

Selecione Resources | JDBC | Connection Pools | IFRJPool e pressione o botão ping a seguinte mensagem deve ser mostrada indicando que o pool de conexão foi criado com sucesso:

Page 27: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceRegistrando o Datasource

Para registrar um datasource, selecione Resources | JDBC | JDBC Resources no lado esquerdo do painel. Na tela que aparece, pressione o botão New.

Os campos devem ser preenchidos da seguinte maneira: • Nome do JNDI – entre como nome lógico da sua aplicação recuperará o DataSource. É recomendado que este nome tenha JDBC como seu prefixo para facilitar para futuros administradores do servidor para identificar este elemento de fonte JDBC (ex. jdbc/IFRJPool)

• Nome do Pool – selecione o nome do pool de conexões criada anteriormente

• Descrição – entre com o texto descrevendo o DataSource (opcional)Pressione o botão OK para finalizar.

Page 28: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceRegistrando o Datasource

Page 29: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceRegistrando o Datasource

Page 30: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceRegistrando o Datasource

Recuperando uma instância de um DataSource de uma aplicação servidora é simples e pode ser realizada usando unicamente algumas linhas de código da API JNDI. Java Naming Directory Interface (JNDI) é uma API Java padrão para acessar diretórios. Um diretório é um local centralizado onde a aplicação Java pode recuperar recursos externos usando um nome lógico.

Necessitamos conhecer que o servidor de aplicação mantém um diretório para que seja publicado o DataSource que foi configurado anteriormente. Nossa própria aplicação pode executar um simples lookup de nome neste diretório para recuperar o recurso.

Para nossas finalidades, é bastante criarmos um contexto JNDI usando o construtor padrão. Este contexto JNDI abstrai os detalhes da conexão para o diretório, fazendo lookup do recurso numa simples chamada num método singular. Tome nota que o nome usado para o lookup na fonte deve ter o mesmo nome usado na configuração no DataSource

Page 31: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceRegistrando o Datasource

... Context ctxt = null; DataSource ds = null; try { // criar uma instância de um contexto JNDI ctxt = new InitialContext(); // retornar o DataSource de um diretório com um nome lógico ds = (DataSource)ctxt.lookup("jdbc/IFRJPool"); } catch (NamingException ne) { System.err("Specified DataSource cannot be found"); }

Page 32: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceRegistrando o Datasource

Uma vez que temos um exemplo de instância DataSource válido, pegarmos um objeto Connection tão simples quanto.Connection conn = ds.getConnection();

Page 33: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourcejava.sql.Connection / java.sql.Statement

Os objetos java.sql.Connection representam conexões reais ao banco de dados. Uma vez que temos um exemplo de um objeto podemos criar uma instância do objeto Statement, para executar as declarações SQL.

O objeto do tipo Statement provê diversos métodos para executar as declarações SQL. Os métodos mais utilizados são:

• executeQuery – utilizado para a instruções de pesquisa no banco de dados (comando SELECT) e retorna o resultado da operação em um objeto do tipo ResultSet.

• executeUpdate – utilizado para as instruções de modificação do banco de dados (comandos CREATE, DROP, ALTER, INSERT, UPDATE ou DELETE) e retorna um tipo primitivo int com o número de linhas afetadas.

Page 34: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourcejava.sql.Connection / java.sql.Statement

Abaixo está um exemplo de pedaço de um código mostrando como realizar este procedimento:Context ctxt = null; DataSource ds = null; Connection conn = null; Statement stmt = null; ResultSet rs = null; try { ctxt = new InitialContext(); ds = (DataSource)ctxt.lookup("jdbc/IFRJPool"); conn = ds.getConnection(); stmt = conn.createStatement(); rs = stmt.executeQuery("SELECT * FROM TEST");} catch (NamingException e) { System.err.print("Cannot find named datasource"); } catch (SQLException se) { System.err.print("Error occurred while performing query"); }

Page 35: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourcejava.sql.ResultSet

Um objeto ResultSet é o resultado de uma consulta em um banco de dados. Os dados dentro de um objeto ResultSet podem ser melhor visualizados com uma tabela. As informações podem ser recuperada uma coluna de cada vez, com o objeto ResultSet que mantem-se apontando para determinado registro.

Para percorrer cada linha no ResultSet, chamamos o método next(). Este método move-se a um ponto interno do objeto ResultSet para a próxima linha. Retorna true se a próxima linha for encontrada e false ao encontrar o final de arquivo (EOF).

while (rs.next()) { // ler cada coluna}

Page 36: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourcejava.sql.ResultSet

Para recuperar os campos em cada linha, o objeto ResultSet fornece um certo de número de métodos de recuperação. Existe um método getString para recuperar dados de uma String, um método getInt para recuperar dados do tipo inteiro, getBoolean para recuperar dados tipo boolean, e assim sucessivamente. Em todos os casos esses métodos recebem um parâmetro, como o número da coluna da coluna que contém o dado ou o nome da coluna. Recomenda-se, entretanto, que nomes sejam usados para especificar a coluna para ser lida em vez do número de linhas. Isto faz com que a aplicação seja mais fácil de dar manutenção, pois é possível que a ordem da coluna seja alterada ao longo do tempo após o início do desenvolvimento.

Page 37: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourcejava.sql.ResultSet

//import java.sql.*; import javax.naming.*; import javax.sql.* ;Context ctxt = null; DataSource ds = null; Connection conn = null; Statement stmt = null; ResultSet rs = null; try { ctxt = new InitialContext(); ds = (DataSource)ctxt.lookup("jdbc/PostgreSQLDS"); conn = ds.getConnection(); stmt = conn.createStatement(); rs = stmt.executeQuery("SELECT * FROM users"); while (rs.next()) { String userName = rs.getString("name"); String address = rs.getString("address"); int userID = rs.getInt("userid"); // Outras operações com os dados retornados }}

Page 38: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourcejava.sql.ResultSet

catch (NamingException e) { System.err("Cannot find named datasource"); } catch (SQLException se) { System.err("Error occurred while performing query"); }

Page 39: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceLiberando recursos do sistema

Uma etapa muito importante, que é negligenciada freqüentemente, é a de liberar os recursos de banco de dados depois de uma operação ter sido completada. Isto deve ser feito explicitamente e é de responsabilidade do programador. Sem executar tal liberação, os recursos mencionados pela operação acima NÃO podem ser usados futuramente. Para aplicações de larga escala, isto pode rapidamente resultar em perda de disponibilidade de conexões.

A liberação de recursos pode ser feita pela chamada do método close() em cada um dos objetos Connection, Statement e ResultSet. Há uma ordem específica envolvida: o objeto do tipo ResultSet deve ser fechado primeiro, em seguida o objeto do tipo Statement e, finalmente o objeto do tipo Connection. Já que cada método de fechamento de cada objeto foi definido para lançar uma SQLException, deve-se envolver as instruções em um bloco try-catch.

Um erro comum que os desenvolvedores fazem é simplesmente colocar métodos de fechamento dentro do corpo do bloco try-catch.

Page 40: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceLiberando recursos do sistema

Context ctxt = null; DataSource ds = null; Connection conn = null; Statement stmt = null; ResultSet rs = null;try { ctxt = new InitialContext(); ds = (DataSource)ctxt.lookup("jdbc/PostgreSQLDS"); conn = ds.getConnection(); stmt = conn.createStatement(); rs = stmt.executeQuery("SELECT * FROM users"); while (rs.next()) { String userName = rs.getString("name");

Page 41: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceLiberando recursos do sistema

String address = rs.getString("address"); int userID = rs.getInt("userid"); // Outras operações com os dados retornados } rs.close(); stmt.close(); conn.close();} catch (NamingException e) { System.err("Cannot find named datasource"); } catch (SQLException se) { System.err("Error occurred while performing query"); }

Page 42: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceLiberando recursos do sistema

O problema com esta abordagem é que condiciona o sucesso um único endereço. Nos casos onde uma exceção ocorre no código os recursos de sistema NÃO serão liberados corretamente. Um caminho melhor será colocar a clausula finally, para assegurar que os recursos sejam liberados não importando o que aconteça. A solução para o problema é apresentada a seguir:

Page 43: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceLiberando recursos do sistema

catch (NamingException e) { System.err("Cannot find named datasource"); } catch (SQLException se) { System.err("Error occurred while performing query"); } finally { try { if (rs != null) rs.close(); } catch (SQLException e) {} try { if (stmt != null) stmt.close(); } catch (SQLException e) {} try { if (conn != null) conn.close(); } catch (SQLException e) {} }

Page 44: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

javax.sql.DataSourceLiberando recursos do sistema

Os questionamentos sobre se o objeto é nulo são necessários apenas nos casos em que a condição de erro ocorra antes de um ou mais objetos terem sido apropriadamente instanciados. Cada método close deve também ser separado numa clausula try-catch para assegurar que um erro causado na tentativa de fechamento de um objeto não atrapalhe o fechamento dos outros objetos.

Page 45: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A conexão em Java

--------------------------------------

Page 46: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A conexão em Java

Fábrica de ConexõesEm determinado momento de nossa aplicação, gostaríamos de ter o controle sobre a construção dos objetos da nossa classe. Muito pode ser feito através do construtor, como saber quantos objetos foram instanciados ou fazer o log sobre essas instanciações.Às vezes, também queremos controlar um processo muito repetitivo e trabalhoso, como abrir uma conexão com o banco de dados. Tomemos como exemplo a classe a seguir que seria responsável por abrir uma conexão com o banco:

Page 47: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A conexão em Java

public class ConnectionFactory {public Connection getConnection() { try { return DriverManager.getConnection("jdbc:mysql://localhost/base","root",""); } catch(SQLException e) { throw new RuntimeException(e);}}}

Page 48: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A conexão em Java

Poderíamos colocar um aviso na nossa aplicação, notificando todos os programadores a adquirir uma conexão:Connection con = new ConnectionFactory().getConnection();Note que o método getConnection() é uma fábrica de conexões, isto é, ele cria novas conexões para nós. Basta invocar o método e recebemos uma conexão pronta para uso, não importando de onde elas vie-ram e eventuais detalhes de criação. Portanto, vamos chamar a classe de ConnectionFactory e o método de getConnection.Encapsulando dessa forma, podemos mais tarde mudar a obtenção de conexões, para, por exemplo, usar um mecanismo de pooling, que é fortemente recomendável em uma aplicação real.

Page 49: Introdução à programação para web com Java -  Módulo 01: Conexão com bamco de dados (JDBC)

A conexão em Java

Tratamento de ExceçõesRepare que estamos fazendo um try/catch em SQLException e relançando-a como uma RuntimeException. Fazemos isso para que o seu código que chamará a fábrica de conexões não fique acoplado com a API de JDBC. Toda vez que tivermos que lidar com uma SQLException, vamosrelançá-las como RuntimeException.Poderíamos ainda criar nossa própria exceção que indicaria que ocorreu um erro dentro da nossa Factory, algo como uma ConnectionFactoryException.