JDBC (Fundamentos) Sang Shin Java Technology Architect Sun Microsystems, Inc. [email protected] www.javapassion.com 1 Agenda • • • • • O que é JDBC? Passo a passo do uso da API JDBC DataSource & pool de Conexões Transações Prepared and Callable Statements 2 O que é JDBC? 3 O que é JDBC? • A API Java padrão para acessar bases de dados relacionais – • Esconde da aplicação os detalhes específicos do banco de dados Parte do Java SE (J2SE) – Java SE 6 tem o JDBC 4 4 A API JDBC • Define um conjunto de interfaces Java, as quais são implementadas por Drivers JDBC específicos para o SGBD em uso – • A maior parte da API JDBC está localizada no pacote java.sql – • As aplicações usam esse conjunto de interfaces Java para realizar operações no banco de dados → portabilidade DriverManager, Connection, ResultSet, DatabaseMetaData, ResultSetMetaData, PreparedStatement, CallableStatement e Types Outras funcionalidades avançadas, estão disponíveis no pacote javax.sql – DataSource 5 O driver JDBC • Implementação das interfaces JDBC para um banco de dados específico – • Todo SGBD tem um (ou mais) driver(s) JDBC específicos Você pode encontrar a lista de drivers disponíveis em: – http://industry.java.sun.com/products/jdbc/drivers 6 URL do Banco de Dados • Usada para estabelecer uma conexão com o banco de dados – • Pode conter o servidor, porta, protocolo, etc. jdbc:subprotocol:subname – Derby jdbc:derby://host_name:port/dbname – Oracle Type 4 JDBC Driver. jdbc:oracle:thin:@machine_name:port_number:instance_name – MySQL Connector/J JDBC Driver. jdbc:mysql://host_name:port/dbname 7 Passo a passo Uso da API JDBC 8 Passos para usar JDBC • Carregue o driver JDBC específico para o banco de dados em uso • Obtenha um objeto Connection • Obtenha um objeto Statement • Execute consultas e/ou atualizações • Leia os resultados • Leia os metadados (opcional) • Feche os objetos Connection e Statement 9 1. Carregue o driver JDBC específico para o banco de dados em uso • Para carregar manualmente o driver do banco de dados e registrá-lo com o DriverManager carregue o arquivo .class – Class.forName(<driver do banco de dados>) 10 Exemplo: carregando uma instância do driver JDBC 11 2. Obtenha um objeto Connection • A classe DriverManager é responsável por selecionar o banco de dados e por criar a conexão com o banco de dados – • A maneira preferível de obter um objeto Connection é através da classe DataSource (falaremos sobre isso mais tarde) Crie a conexão com o banco de dados da seguinte forma: 12 DriverManager & Connection • java.sql.DriverManager – • getConnection(String url, String user, String password) throws SQLException java.sql.Connection – – – – – Statement createStatement() throws SQLException void close() throws SQLException void setAutoCommit(boolean b) throws SQLException void commit() throws SQLException void rollback() throws SQLException 13 3. Obtenha um objeto Statement • • Use o objeto Connection para obter uma instância de Statement – java.sql.Statement • ResultSet executeQuery(String sql) • int executeUpdate(String sql) – Exemplo: O mesmo objeto Statement pode ser usado para várias consultas não relacionadas 14 4. Execute consultas e/ou atualizações • A partir do objeto Statement, os dois comandos mais utilizados são: – CONSULTA (SELECT) – ALTERAÇÕES (INSERT/UPDATE/DELETE) 15 5. Leia os resultados • Percorra o ResultSet (usando um laço) recuperando informações – • java.sql.ResultSet • boolean next() • xxx getXxx(int numeroColuna) • xxx getXxx(String nomeColuna) • void close() O iterator é inicializado em uma posição anterior à primeira linha – Você deve chamar next() uma vez para mover o cursor para a primeira linha 16 5. Leia os resultados (continuação) • Uma vez obtido um ResultSet (através de um statement.executeQuery()), você pode recuperar facilmente os dados percorrendo o ResultSet 17 5. Leia os resultados (continuação) • Ao recuperar os dados de um ResultSet, use o método getXxx() apropriado – – – – • getString() getInt() getDouble() getObject() Existe um método getXxx apropriado para cada tipo de dados definido em java.sql.Types 18 6. Leia os metadados do ResultSet e do banco de dados (opcional) • Uma vez que você disponha dos objetos ResultSet ou Connection, é possível obter os metadados do banco de dados ou da consulta • Dessa forma, é possível obter informações valiosas sobre o dado que você está recuperando ou sobre o banco de dados que você está usando 19 Exemplo de DatabaseMetaData • A classe DatabaseMetaData tem, aproximadamente, 150 métodos 20 DataSource & Pool de Conexões 21 Sub-Tópicos • A interface DataSource e o objeto DataSource • Propriedades do objeto DataSource • Registro JNDI de um objeto DataSource • Objeto DataSource que implementa um pool de conexões • Recuperação de um objeto DataSource (dentro de sua aplicação) 22 A Interface javax.sql.DataSource e o Objeto DataSource • Os vendedores do driver JDBC implementam a interface • O objeto DataSource é a fábrica para a criação de conexões com o banco de dados 23 A Interface javax.sql.DataSource e o Objeto DataSource • Três tipos de implementações possíveis: – Implementação básica: gera objetos Connection padrão – Implementação de um pool de conexões: gera um objeto Connection que, automaticamente, faz parte de um pool de conexões – Implementação de transações distribuídas: produz um objeto Connection que pode ser usado para transações distribuídas e, quase sempre, participa de um pool de conexões 24 Propriedades de um objeto DataSource • Um objeto DataSource tem propriedades que podem ser modificadas quando necessário – essas são definidas em um arquivo de configuração do container – localização do servidor de bancos de dados – nome do banco de dados – protocolo de rede usado para comunicar com o servidor • Benefício: uma vez que as propriedades do objeto DataSource podem ser alteradas, qualquer código que acessa a fonte de dados não precisa ser alterado • No servidor de aplicações da Sun, uma fonte de dados é chamada de um recurso JDBC 25 Onde são definidas as propriedades de um DataSource? • Em um arquivo de configuração do container • No servidor de aplicações da Sun, elas são definidas em – • <J2EE_HOME>/domains/domain1/config/domain.xml No Tomcat, elas são definidas no arquivo server.xml – <TOMCAT_HOME>/conf/server.xml 26 A definição de uma fonte de dados (recurso JDBC) no arquivo domain.xml (Sun App Server) 27 28 29 Registro JNDI de um objeto DataSource • Um driver acessado através de um objeto DataSource não registra a si mesmo junto ao DriverManager • Ao invés disso, um objeto DataSource é registrado pelo container em um serviço de nomes JNDI e então é recuperado pelo cliente através de uma operação de pesquisa • Em uma implementação básica, a conexão obtida através de um objeto DataSource é idêntica àquela obtida através de uma facilidade do DriverManager 30 Registro JNDI de um objeto DataSource (Recurso JDBC) • O nome JNDI de um recurso JDBC é esperado no subcontexto java:comp/env/jdbc – • Por exemplo, o nome JNDI do recurso correspondente ao banco de dados BookDB poderia ser: java:comp/env/jdbc/BookDB Uma vez que todos os nomes JNDI estão no subcontexto java:comp/env, quando você especificar o nome de um recurso JDBC, entre somente jdbc/nome. Por exemplo, para um banco de dados de pagamentos, especifique jdbc/BookDB 31 Por que um pool de conexões? • Uma conexão a um banco de dados é um recurso caro e limitado – • Usando um pool de conexões, um número menor de conexões podem ser compartilhadas por um número maior de clientes. Criar e destruir conexões a um banco de dados são operações caras – Em um pool de conexões, um conjunto de conexões é pré-criado e disponibilizado à medida em que as aplicações solicitam conexões. Reduz-se assim o overhead de criar e destruir conexões ao banco de dados. 32 Pool de conexões e objetos DataSource • Objetos DataSource que implementam um pool de conexões também produzem uma conexão para a fonte de dados particular representada pela classe DataSource • O objeto conexão retornado pelo método getConnection é um handler para um objeto do tipo PooledConnection, ao invés de uma conexão física – O código da aplicação funciona da mesma forma 33 Exemplo: Criando um recurso JDBC no SJSAS (Glassfish) • Vamos criar um recurso JDBC para acessar um banco de dados SQL 1. Obtenha o driver JDBC para o MySQL no endereço http://dev.mysql.com/downloads/connector/j/5.1.html 2. Mova o arquivo mysql-connector-java-5.1.6-bin.jar para o diretório "%J2EE_HOME%\lib\ext\" 3. (Re)Inicie o Servidor de Aplicações e, no console do Administrador, crie uma nova Connection Pool Common Tasks → Other Tasks → Create New JDBC Connection Pool 34 Exemplo: Criando um recurso JDBC no SJSAS (Glassfish) 4. Use os seguintes valores: Name: MySQLPool Resource Type: javax.sql.ConnectionPoolDataSource Database Vendor: MySQL [NEXT] 5. Preencha os seguintes valores para as propriedades adicionais: ServerName: 127.0.0.1 User: (um usuário existente) Password: (a password do usuário) URL: jdbc:mysql://localhost/<nome do banco de dados> [FINISH] 35 Exemplo: Criando um recurso JDBC no SJSAS (Glassfish) 6. Associe a Connection Pool criada a um nome JNDI Resources → JDBC → JDBC Resources → New 7. Na tela que se abre, preencha os campos conforme a figura a seguir e, em seguida, pressione o botão OK. 36 Recuperação e uso de um objeto DataSource • A aplicação realiza uma operação de busca JNDI para recuperar um objeto DataSource • O objeto DataSource é então usado para recuperar um objeto Connection • O arquivo do servidor de aplicações domain.xml é usado para fornecer informações sobre o recurso externo • O mapeamento do recurso externo para o nome JNDI é também realizado no Sun Java System Application Server (SJSAS) 37 Exemplo: Recuperação de um objeto DataSource através do JNDI public class TestDBAO { Connection con; public void operation() { try { Context initCtx = new InitialContext(); DataSource ds =(DataSource)initCtx.lookup( "jdbc/testDB"); con = ds.getConnection(); // ... } catch (Exception ex) { } } } 38 Transações 39 Transações • Um dos principais benefícios do uso de um PreparedStatement é executar os comandos SQL em um modo transacional. • A confirmação de cada comando, assim que ele é executado, gasta muito tempo • Atribuindo o valor false à propriedade AutoCommit, o desenvolvedor pode atualizar a base de dados mais de uma vez e então confirmar toda a transação como um todo • Além disso, se cada comando é dependente do outro, toda a transação pode ser desfeita e o usuário notificado. 40 Métodos de uma Transação JDBC • setAutoCommit() – • • se true, cada comando executado é imediatamente confirmado commit() – relevante somente se setAutoCommit(false) – Confirma as operações realizadas desde a abertura de uma conexão ou desde a última chamada a um commit() ou a um rollback() rollback() – relevante somente se setAutoCommit(false) – cancela todas as operações pendentes 41 Exemplo de Transações 42 43 Prepared & Callable Statements 44 O que são? • PreparedStatement – • SQL é enviado para o banco de dados e compilado ou preparado antecipadamente CallableStatement – Executa as Stored Procedures 45 PreparedStatement • O comando SQL é enviado para o Banco de Dados e compilado ou preparado antecipadamente • Desse ponto em diante, o comando SQL preparado é enviado e esse passo não mais é executado. O objeto Statement requer esse passo em toda execução. • Dependendo do mecanismo do BD, o comando SQL pode ir para um cache e reutilizado, mesmo que outro objeto PreparedStatement seja utilizado. Nesse caso, a maior parte do trabalho é feita pelo BD e não pelo driver. 46 PreparedStatement (cont.) • Um PreparedStatement pode receber N parâmetros correspondentes aos valores das colunas. Esses argumentos funcionam de maneira muito similar aos argumentos de um método. • Os PreparedStatements lidam com as conversões de dados que podem ser propensas a erros quando construídas direta e apressadamente em SQL – manipulação de aspas e datas de uma maneira transparente para o usuário 47 Passos para a utilização de um PreparedStatement 1. Registre o driver e crie a conexão com o BD da forma usual. 2. Uma vez que você tenha a conexão ao BD, crie o objeto PreparedStatement 48 Passos para a utilização de um PreparedStatement (cont.) 3. Atribua valores aos parâmetros do comando. A referência aos parâmetros é posicional. 4. Uma vez que tenham sido atribuídos valores a todos os parâmetros, execute o PreparedStatement 49 Passos para a utilização de um PreparedStatement (cont.) • Se AutoCommit é igual a true, as modificações são confirmadas tão logo o comando seja executado. Desse ponto em diante, você pode reutilizar o objeto PreparedStatement. 50 Passos para a utilização de um PreparedStatement (cont.) • Se o objeto PreparedStatement contém uma declaração SELECT então, após executá-lo, você percorre o ResultSet resultante usando um laço, da mesma forma que fizemos no exemplo de uso dos Statements. 51 CallableStatement • A interface usada para executar stored procedures • Uma stored procedure é um grupo de comandos SQL que formam uma unidade lógica e executam uma tarefa específica • Stored Procedures são usadas para encapsular um conjunto de operações ou consultas a serem executadas em um servidor de bancos de dados. 52 CallableStatement (cont.) • Um objeto do tipo CallableStatement contém uma chamada a uma stored procedure; ele não contém a stored procedure. • A primeira linha do código a seguir cria uma chamada para a stored procedure chamada MOSTRA_PRODUTOS usando a conexão con. • A parte delimitada por chaves contém a sintaxe de escape para a chamada de procedimentos armazenados. 53 Exemplo de Stored Procedure CREATE PROCEDURE `MOSTRA_PRODUTOS`() BEGIN SELECT * FROM Produto; END 54 Exemplo de Stored Procedure • Uma stored procedure pode ainda receber parâmetros. Esses parâmetros pode ser de entrada (IN, default), saída (OUT) e entrada/saída (INOUT) A seguir um exemplo usando parâmetros de entrada e saída: 55 Exemplo MySQL • A seguir um exemplo de código que usa a stored procedure do slide anterior 56