Capítulo 11 Java Data Base Conectivity Introdução Pacote java.sql Abrindo e fechando conexões Operações na base de dados Operações parametrizadas Transações Consultas Stored procedures Design patterns DAO e VO Projeto Final 2 Introdução Arquitetura Cliente/Servidor Cliente Cliente Servidor Oracle MS SQL Server MySql Cliente 3 Introdução JDBC O JDBC (Java Data Base Conectivity) é uma especificação elaborada pela antiga Sun para prover a acessibilidade de aplicações Java com bancos de dados. Trata-se de um padrão de acesso a dados obedecido pela indústria de bancos de dados. A fim de seguir este padrão, os fabricantes devem distribuir drivers JDBC aos desenvolvedores Java. 4 Introdução Tipos de driver APLICAÇÃO JAVA DRIVER TIPO 1 APLICAÇÃO JAVA DRIVER TIPO 2 CONFIG. ODBC COMPONENTE “CLIENT” APLICAÇÃO JAVA DRIVER TIPO 3 APLICAÇÃO JAVA DRIVER TIPO 4 MIDDLEWARE BANCO DE DADOS BANCO DE DADOS BANCO DE DADOS BANCO DE DADOS 5 Introdução Tipos de driver Tipo 1 Driver JDBC que usa a ponte de comunicação ODBC-JDBC para acessar a base pelo antigo padrão ODBC criado pela Microsoft. O ODBC trata-se de um antigo padrão de acessibilidade desenvolvido pela Microsoft que ainda pode ser utilizado no acesso a fontes de dados legadas tais como Fox Pro, DBase, Clipper, Access, etc. 6 Introdução Tipos de driver Tipo 2 Um driver se enquadra no tipo 2 quando necessita de algum software complementar instalado na estação de trabalho (máquina cliente) para acessar a base de dados. Utilizam API’s auxiliares e requerem a instalação de algum componente adicional nativo ao Sistema Operacional. 7 Introdução Tipos de driver Tipo 3 Tipo de driver que necessita de uma API de rede via middleware geralmente instalado no próprio servidor de dados para traduzir requisições para o driver desejado. Não requer nenhum software adicional no cliente além do driver JDBC. 8 Introdução Tipos de driver Tipo 4 Driver que se comunica diretamente com o banco de dados usando puramente soquetes de rede. É desenvolvido pelo fabricante totalmente em Java. Não requer código adicional do lado do cliente nem no servidor. É simples de usar e possui melhor performance que os demais tipos. 9 Introdução Alguns drivers Microsoft SQL Server JDBC Driver ○ sqljdbc4.jar MySql Connector / J ○ mysql-connector-java-5.1.20-bin.jar Oracle JDBC ○ ojdbc6.jar (antigo classes12.jar) 10 Pacote java.sql Contém classes utilizadas no acesso e manipulação de dados externos via JDBC. 11 Pacote java.sql DriverManager Statement Connection PreparedStatement CallableStatement 0..1 0..1 ResultSet SQLException 0..* 12 Abrindo e fechando conexões Carregamento do driver Antes de solicitar uma conexão com a base de dados, devemos primeiramente realizar o carregamento do driver para a memória através do comando: Class.forName(“com.mysql.jdbc.Driver”) O comando Class.forName(“...”) realiza o carregamento de alguma classe para a memória sem criar instâncias. 13 Abrindo e fechando conexões Carregamento do driver O método forName() requer o tratamento da exception ClassNotFoundException que pode ocorrer na aplicação caso o driver não esteja no classpath: try { Class.forName(“com.mysql.jdbc.Driver”); } catch (ClassNotFoundException e) { System.out.println(“Não foi possível carregar o driver.”); } 14 Abrindo e fechando conexões Abrindo a conexão com a base de dados. A interface java.sql.Connection representa uma conexão com a base de dados e é o ponto de partida para realizarmos qualquer tipo de operação com esta. Podemos obtem uma Connection (abrir uma conexão) utilizando a classe java.sql.DriverManager: Connection cn = DriverManager.getConnection( “jdbc:mysql://sigma.server.com.br:3306/dbtest”, “usuario”, “senha”); 15 Abrindo e fechando conexões Abrindo a conexão com a base de dados. DriverManager.getConnection( “jdbc:mysql://sigma.server.com.br:3306/dbtest”, “usuario”, “senha”); URL de conexão (Caminho/endereço do servidor) Usuário Senha 16 Abrindo e fechando conexões URL de conexão A URL de conexão define o caminho do servidor de dados e é específico para cada driver utilizado: jdbc:mysql://servidor:3306/database jdbc:sqlserver://servidor\instancia:1433;databaseName=database jdbc:oracle:thin:@servidor:1521:instancia 17 Abrindo e fechando conexões Fechando a conexão Após encerrarmos todas as operações com a base de dados devemos fechar a conexão utilizada: cn.close(); Conexão utilizada no acesso à base de dados 18 Abrindo e fechando conexões Fechando a conexão Tanto a abertura quanto o fechamento da conexão requerem o tratamento da exceção SQLException: try { Class.forName(“com.mysql.jdbc.Driver”); Connection cn = DriverManager.getConnection( “jdbc:mysql://server:3306/db”, “usuario”, “senha”); /* ... operações com a base de dados ... */ cn.close(); } catch (ClassNotFoundException e) { System.out.println(“Não foi possível carregar o driver.”); } catch (SQLException e) { System.out.println(“Falha ao conectar à base de dados.”); } 19 Operações na base de dados Com a conexão aberta podemos realizar operações na base de dados, como inclusão, exclusão, alteração e outros. Cada operação na base de dados é definida por uma instrução na linguagem SQL, chamada de “statement”: UPDATE tab_funcionario SET salario = 5000 WHERE matr = 34 INSERT INTO tab_setor (codigo, nome) VALUES (34, ‘RH’) DELETE FROM tab_produto WHERE codigo = 4983 20 Operações na base de dados Interfaces statements: Statement PreparedStatement CallableStatement 21 Operações na base de dados Interfaces statements: Statement Utilizado para executar instruções SQL simples e prédefinidas. PreparedStatement Utilizado para executar instruções SQL parametrizadas. CallableStatement Utilizado para executar stored procedures e functions 22 Operações na base de dados A interface Statement Utilizado para execução de simples instruções SQL Conexão utilizada no acesso à base de dados Statement st = cn.createStatement(); st.executeUpdate(“UPDATE tab_func SET salario = salario + 200”); st.executeUpdate(“DELETE FROM tab_func”); st.executeUpdate(“INSERT INTO tab_cargo (nome) VALUES (‘RH’)”); st.executeUpdate(“CREATE TABLE tab_produto (...)”); st.close(); 23 Operações parametrizadas A interface PreparedStatement Principal tipo de statement utilizado no acesso e manipulação de dados da base Representa alguma instrução SQL parametrizada, onde alguns de seus valores são dinamicamente assinalados pela aplicação A principal vantagem do PreparedStatement é que sua instrução pode ser executada diversas vezes, cada hora com valores diferentes. 24 Operações parametrizadas A interface PreparedStatement Exemplo 1 Conexão utilizada no acesso à base de dados PreparedStatement ps = cn.prepareStatement( “INSERT INTO tab_func (matricula, nome, salario) VALUES (?, ?, ?)”); ps.setInt(1, 1001); ps.setString(2, “José Souza”); ps.setDouble(3, 3200.45); ps.executeUpdate(); ps.close(); 1 2 3 25 Operações parametrizadas A interface PreparedStatement Exemplo 2 Conexão utilizada no acesso à base de dados PreparedStatement ps = cn.prepareStatement( “UPDATE tab_func SET salario = ? WHERE matricula = ?”); ps.setDouble(1, 3200.45); ps.setInt(2, 1001); ps.executeUpdate(); 1 2 ps.setDouble(1, 7350.92); ps.setInt(2, 1005); ps.executeUpdate(); ps.close(); 26 Operações parametrizadas A interface PreparedStatement Ao criar um PreparedStatement devemos especificar a declaração SQL que será executada contendo caracteres de interrogação ?. Cada interrogação contida na declaração SQL representa um parâmetro – um valor a ser assinalado dinamicamente na aplicação. Um PreparedStatement deve ter todos os seus valores assinalados antes de ser executado. 27 Operações parametrizadas Tipos de parâmetros Tipo SQL Método set Tipo Java CHAR, VARCHAR setString() java.lang.String INT, DECIMAL, NUMERIC (sem parte fracionária) setInt() int DOUBLE, DECIMAL, NUMERIC (podendo haver parte fracionária) setDouble() double BOOLEAN setBoolean() boolean DATE setDate() java.sql.Date TIME setTime() java.sql.Time DATETIME, TIMESTAMP setTimestamp() java.sql.Timestamp BLOB, MEDIUMBLOB, LONGBLOB setBinaryStream() java.io.InputStream NULL setNull() 28 Operações parametrizadas Método setString() Assinala um parâmetro do tipo texto. ps = cn.prepareStatement( “DELETE FROM tab_func WHERE cargo LIKE ?”); ps.setString(1, “Manuel”); ps.executeUpdate(); ps.close(); 29 Operações parametrizadas Método setInt() Assinala um parâmetro numérico sem parte fracionária. ps = cn.prepareStatement( “DELETE FROM tab_func WHERE matricula = ?”); ps.setInt(1, 7012); ps.executeUpdate(); ps.close(); 30 Operações parametrizadas Método setDouble() Assinala um parâmetro numérico podendo possuir parte fracionária. ps = cn.prepareStatement( “UPDATE tab_func SET salario = ?”); ps.setInt(1, 2500.35); ps.executeUpdate(); ps.close(); 31 Operações parametrizadas Método setBoolean() Assinala um parâmetro booleano e armazena na base como 0 (false) ou 1 (true) ps = cn.prepareStatement(“UPDATE tab_func SET ativo = ?”); ps.setBoolean(1, true); ps.executeUpdate(); ps.close(); 32 Operações parametrizadas Método setDate() Assinala um parâmetro do tipo java.sql.Date, que representa uma data (dia, mês e ano) ps = cn.prepareStatement(“UPDATE tab_func SET nasc = ?”); Calendar calendar = Calendar.getInstance(); Calendar.set(1992, 0, 25); /* dia 25/01/1992 */ java.sql.Date date = new java.sql.Date(calendar.getTimeInMillis()); ps.setDate(1, date); ps.executeUpdate(); ps.close(); 33 Operações parametrizadas Método setTime() Assinala um parâmetro do tipo java.sql.Time, que representa um horário (hora, minuto e segundo) ps = cn.prepareStatement(“UPDATE tab_func SET hr_entr = ?”); Calendar calendar = Calendar.getInstance(); Calendar.set(0, 0, 0, 12, 15, 30); /* 12:15:30 */ java.sql.Time time = new java.sql.Time(calendar.getTimeInMillis()); ps.setTime(1, time); ps.executeUpdate(); ps.close(); 34 Operações parametrizadas Método setTimestamp() Assinala um parâmetro do tipo java.sql.Timestamp, que representa um instante no tempo (ano, mês, dia, hora, minuto e segundo) ps = cn.prepareStatement(“UPDATE tab_func SET nasc = ?”); Calendar calendar = Calendar.getInstance(); Calendar.set(1992, 0, 25, 12, 15, 30); /* 25/01/1992 12:15:30 */ Timestamp dateTime = new Timestamp(calendar.getTimeInMillis()); ps.setTimestamp(1, dateTime); ps.executeUpdate(); ps.close(); 35 Operações parametrizadas Método setBinaryStream() Assinala um parâmetro do tipo java.io.InputStream, que representa alguma informação binária, como uma foto, mp3, doc ou outro. ps = cn.prepareStatement(“INSERT INTO tab_foto (foto) VALUES (?)”); ps.setBinaryStream(1, new FileInputStream(“C:\\image\\foto.jpg”)); ps.executeUpdate(); ps.close(); 36 Operações parametrizadas Método setNull() Assinala um parâmetro com o valor NULL ps = cn.prepareStatement( “INSERT INTO tab_func (nome, salario) VALUES (?, ?)”); ps.setString(1, “Manuel silva”); ps.setNull(2); ps.executeUpdate(); ps.close(); 37 Exercício Crie uma aplicação para cadastrar cargos na tabela tab_role. A aplicação deverá solicitar que o usuário digite nomes de cargos em prompt de comando (utilize a classe Scanner). Para cada cargo digitado abra a conexão com a base de dados e execute o comando abaixo passando como parâmetro o cargo digitado pelo usuário: INSERT INTO tab_role (role_name) VALUES (?) 38 Transações Chamamos de transação a um conjunto de operações realizadas na base de dados que podem ser desfeitas em situações de falha ou outro problema. Quando corretamente utilizada, uma transação garante a integridade dos dados contidos na base. Chamamos de rollback ao comando utilizado para desfazer as operações retidas pela transação e commit ao comando utilizado para efetivá-las na base de dados. 39 Transações O JDBC permite a criação de aplicações Java que manipulam transações com bancos de dados que oferecem suporte a este tipo de recurso. Para isto contamos com os seguintes métodos da interface java.sql.Connection: setAutoCommit(boolean) commit() rollback() 40 Transações Exemplo cn = DriverManager.getConnection(...); st = cn.createStatement(); try { cn.setAutoCommit(false); st.executeUpdate(“INSERT INTO tab (...) VALUES (...)”); st.executeUpdate(“INSERT INTO tab (...) VALUES (...)”); st.executeUpdate(“DELETE FROM tab WHERE ...”); st.executeUpdate(“UPDATE tab SET ....”); cn.commit(); } catch (Exception e) { cn.rollback(); } 41 Consultas As consultas na base de dados são realizadas mediante o comando SELECT. Através dele podemos obter os dados contidos em uma ou mais tabelas seguindo critérios, agrupamentos e/ou ordenações conforme necessidade da aplicação. Para capturarmos os dados provenientes do comando SELECT, o JDBC conta com a interface java.sql.ResultSet 42 Consultas O ResultSet Um ResultSet representa um cursor proveniente da base de dados. Trata-se de um conjunto de dados em memória de forma tabular que possui um ponteiro apontando para uma de suas linhas, a qual é chamada de registro atual. 43 Consultas Algum Statement ou PreparedStatement ResultSet rs = st.executeQuery(“SELECT * FROM tab_func”); rs.next(); codigo = rs.getInt(“f_code”); nome = rs.getString(“f_name”); salario = rs.getDouble(“f_rmnt”); ... rs.next(); codigo = rs.getInt(“f_code”); nome = rs.getString(“f_name”); salario = rs.getDouble(“f_rmnt”); ... rs.next(); codigo = rs.getInt(“f_code”); nome = rs.getString(“f_name”); salario = rs.getDouble(“f_rmnt”); ... f_code f_name f_rmnt 1003 Manuel 1.253,86 1004 Joaquim 1008 Maria 1.530,15 1012 Henrique 6.530,45 1039 João 4.350,12 1112 Priscila 843,00 1128 Ricardo 7.815,26 950,60 44 Consultas ResultSet rs = st.executeQuery(“SELECT * FROM tab_func”); while (rs.next()) { codigo = rs.getInt(“f_code”); nome = rs.getString(“f_name”); salario = rs.getDouble(“f_rmnt”); ... } rs.close(); f_code f_name f_rmnt 1003 Manuel 1.253,86 1004 Joaquim 1008 Maria 1.530,15 1012 Henrique 6.530,45 1039 João 4.350,12 1112 Priscila 843,00 1128 Ricardo 7.815,26 950,60 45 Consultas Outro exemplo PreparedStatement ps = cn.prepareStatement( “SELECT f_name, f_rmnt FROM tab_func WHERE salario > ?”); ps.setDouble(1, 1000); ResultSet rs = ps.executeQuery(); while (rs.next()) { nome = rs.getString(“f_name”); salario = rs.getDouble(“f_rmnt”); ... } rs.close(); 46 Exercício Crie uma aplicação que solicite ao usuário que digite um nome ou o pedaço de um nome. Realize uma busca na tabela de funcionários exibindo na tela o nome e salário de todos os usuários que possuam o pedaço de nome digitado. Utilize a consulta abaixo para obter os dados da base: SELECT func_name, func_rmnt FROM tab_func WHERE func_name LIKE ? 47 Stored procedures Chamamos de Stored Procedure a um conjunto de instruções SQL que juntas formam um pequeno programa armazenado e executado no banco de dados. Alguns bancos de dados como MS SQL, Oracle, MySQL, Postgree e outros permitem este tipo de recurso. O uso de Stored Procedures pode reduzir o tráfego na rede, melhorar a performance ou criar mecanismos de segurança ao realizar alguma operação na base de dados. 48 Stored procedures As Stored Procedures são semelhantes a métodos Java. Podem possuir parâmetros e valores de retorno. CREATE PROCEDURE prc_calcula_juros( IN p_valor_inicial DECIMAL(10,2), IN p_taxa DOUBLE, IN p_prazo INTEGER, OUT p_valor_final DECIMAL(10,2)) BEGIN ... ... ... ... ... ... END; 49 Stored procedures A interface CallableStatement No JDBC podemos solicitar a execução de uma Stored Procedure através da interface java.sql.CallableStatement CallableStatement cs = cn.prepareCall(“{ call prc_calcula_juros(?, ?, ?, ?) }”); cs.setDouble(1, 100.0); cs.setDouble(2, 0.1); cs.setInt(3, 2); cs.registerOutParameter(4, Types.DOUBLE); cs.executeUpdate(); double result = cs.getDouble(4); 50 Stored procedures A interface CallableStatement Para obter uma instância de CallableStatement utilizamos o método prepareCall() sobre a conexão com a base. Devemos neste momento informar o String de execução da Stored Procedure desejada: CallableStatement cs = cn.prepareCall(“{ call prc_calcula_juros(?, ?, ?, ?) }”); Conexão utilizada no acesso à base de dados Nome da procedure Parâmetros 51 Stored procedures A interface CallableStatement Os parâmetros de entrada (IN) devem ser todos preenchidos conforme seu tipo, inserindo os valores desejados: cs.setDouble(1, 100.0); /* Parâmetro 1 */ cs.setDouble(2, 0.1); /* Parâmetro 2 */ cs.setInt(3, 2); /* Parâmetro 3 */ 52 Stored procedures A interface CallableStatement Os parâmetros de saída (OUT) devem ser todos registrados conforme seu tipo, informando ao JDBC que estes são valores que serão retornados pela procedure. Para informar o tipo de retorno, utilize uma das constantes da classe java.sql.Types: cs.registerOutParameter(4, Types.DOUBLE); /* Parâmetro 4 */ 53 Stored procedures A interface CallableStatement Após preenchidos e/ou registrados todos os parâmetros, podemos executar a procedure com o método executeUpdate() Após executada a procedure, podemos recolher os valores de retorno provenientes dos parâmetros de saída cs.executeUpdate(); double result = cs.getDouble(4); Número do parâmetro de saída 54 Exercício (parte 1) A procedure prc_numero_descricao foi criada em MySql para fornecer a descrição por extenso de um número inteiro especificado. Para tal, esta procedure possui dois parâmetros: Parâmetro 1: ○ Nome: p_numero ○ Tipo: INTEGER ○ I/O: IN (entrada) Parâmetro 2: ○ Nome: p_descricao ○ Tipo: VARCHAR(100) ○ I/O: OUT (saída) CREATE PROCEDURE prc_numero_descricao( IN p_numero INTEGER, OUT p_descricao VARCHAR(100)) 55 Exercício (fim) Crie uma aplicação Java que solicite que o usuário digite um número inteiro. Execute a procedure prc_numero_descricao passando o número inteiro digitado pelo usuário. Resgate o valor de retorno (parâmetro 2) da procedure e exiba-o na tela. 56 Design pattern DAO/VO 57 Projeto Final 58