Java 16 Jdbc

5,243 views

Published on

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,243
On SlideShare
0
From Embeds
0
Number of Embeds
2,070
Actions
Shares
0
Downloads
216
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Java 16 Jdbc

  1. 1. JDBC Java Database Connectivity <ul><ul><li>Regis Pires Magalhães </li></ul></ul><ul><ul><li>[email_address] </li></ul></ul>
  2. 2. Problema <ul><li>Comunicação com o banco via sockets </li></ul><ul><ul><li>Todo banco de dados possui um protocolo proprietário que pode ser acessado via sockets. </li></ul></ul><ul><ul><li>Poderíamos então abrir sockets diretamente com o banco de dados para realizar os comandos que desejássemos. </li></ul></ul><ul><li>Desvantagens: </li></ul><ul><ul><li>Lidar com a complexidade dos protolocos proprietários de banco de dados. </li></ul></ul><ul><ul><li>Aprender um novo protocolo para cada banco de dados que quiséssemos acessar. </li></ul></ul>
  3. 3. Solução <ul><li>JDBC é uma interface para acesso a bancos de dados através de SQL. </li></ul><ul><ul><li>Permite o acesso a bancos de dados de forma padronizada </li></ul></ul><ul><ul><li>Código SQL é usado explicitamente dentro do código Java </li></ul></ul><ul><ul><li>API única, independente do Banco de Dados </li></ul></ul><ul><ul><li>Pacote: java.sql </li></ul></ul><ul><li>Para usar JDBC é preciso ter um driver JDBC </li></ul><ul><ul><li>O banco deve ter pelo menos um driver ODBC, se não tiver driver JDBC </li></ul></ul><ul><ul><li>No JDK há um driver ODBC que permite o acesso a bancos </li></ul></ul>
  4. 4. JDBC
  5. 5. Categorias de Drivers <ul><li>Tipo 1: ponte JDBC-ODBC </li></ul><ul><ul><li>Usam uma ponte para ter acesso a um banco de dados. Este tipo de solução requer a instalação de software do lado do cliente. </li></ul></ul><ul><li>Tipo 2: solução com código nativo </li></ul><ul><ul><li>Usam uma API nativa. Esses drivers contém métodos Java implementados em C ou C++. Requer software no cliente. </li></ul></ul><ul><li>Tipo 3: solução 100% Java no cliente </li></ul><ul><ul><li>Oferecem uma API de rede via middleware que traduz requisições para API do driver desejado. Não requer software no cliente. </li></ul></ul><ul><li>Tipo 4: solução 100% Java </li></ul><ul><ul><li>Drivers que se comunicam diretamente com o banco de dados usando soquetes de rede. É uma solução puro Java. Não requer código adicional do lado do cliente. </li></ul></ul>
  6. 6. Categorias de Drivers
  7. 7. JavaDB = SUN + Apache Derby <ul><li>A partir do Java 6 a Sun incorporou um banco de dados 100% Java chamado JavaDB. </li></ul><ul><li>Baseado no banco Derby do projeto Apache, que por sua vez veio do banco Cloudscape que foi doado ao projeto Apache pelas empresas Cloudscape, Informix e IBM. </li></ul>
  8. 8. JavaDB = SUN + Apache Derby <ul><li>Vantagens: </li></ul><ul><ul><li>flexibilidade (cliente/server ou embarcado); </li></ul></ul><ul><ul><li>suporte das principais IDE’s (Netbeans e Eclipse). </li></ul></ul><ul><ul><li>Pequeno: cerca de 2MB </li></ul></ul><ul><ul><li>Inclui views, triggers, stored procedures e foreign keys. </li></ul></ul><ul><ul><li>Suporta transações multi-usuário, utilizando os principais níveis de isolação e de propriedades ACID. </li></ul></ul><ul><ul><li>Segurança com encriptação de dados </li></ul></ul><ul><ul><li>Autenticação no lado do cliente </li></ul></ul><ul><ul><li>Comandos GRANT e REVOKE. </li></ul></ul><ul><ul><li>Segue padrões como JDBC 4.0 e SQL92/99/2003/XML. </li></ul></ul>
  9. 9. JavaDB = SUN + Apache Derby Embarcado Cliente-Servidor
  10. 10. JavaDB = SUN + Apache Derby <ul><li>Inicializando o servidor: </li></ul><ul><ul><li>java -jar derbyrun.jar server start </li></ul></ul><ul><li>Executando o ij: </li></ul><ul><ul><li>java -jar derbyrun.jar ij </li></ul></ul><ul><ul><li>ou </li></ul></ul><ul><ul><li>Pode-se colocar os arquivos derby.jar e derbytools.jar no classpath e executar o método main da classe org.apache.derby.impl.tools.ij.Main : </li></ul></ul><ul><ul><ul><li>java -classpath derby.jar;derbytools.jar org.apache.derby.impl.tools.ij.Main </li></ul></ul></ul>
  11. 11. JavaDB = SUN + Apache Derby <ul><li>Usando o ij </li></ul><ul><ul><li>ij> connect 'jdbc:derby:posbd4; create=true'; </li></ul></ul><ul><ul><li>ij> show tables; </li></ul></ul><ul><ul><li>ij> CREATE TABLE clientes (id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, cpf VARCHAR(11), nome VARCHAR(50), fone VARCHAR(10), renda DECIMAL(12, 2)); </li></ul></ul><ul><ul><li>ij> describe clientes; </li></ul></ul><ul><ul><li>ij> SELECT * FROM CLIENTES; </li></ul></ul><ul><ul><li>ij> create table tabela1(num int, addr varchar(40)); </li></ul></ul><ul><ul><li>ij> insert into tabela1 values (1956,'Webster St.'); </li></ul></ul><ul><ul><li>ij> insert into tabela1 values (1910,'Union St.'); </li></ul></ul><ul><ul><li>ij> update tabela1 set num=180, addr='Grand Ave.' where num=1956; </li></ul></ul><ul><ul><li>ij> select * from tabela1; </li></ul></ul><ul><ul><li>ij> disconnect; </li></ul></ul><ul><ul><li>ij> exit; </li></ul></ul>
  12. 12. Passos para uso do JDBC <ul><li>Adicionar o driver JDBC ao classpath </li></ul><ul><li>Carregar a classe do driver JDBC </li></ul><ul><li>Estabelecer a conexão a partir de uma URL </li></ul><ul><li>Criar um Statement </li></ul><ul><li>Executar uma query ou update </li></ul><ul><li>Processar os resultados </li></ul><ul><li>Fechar a conexão </li></ul>
  13. 13. Conectando com o banco <ul><li>Adicionar o driver JDBC ao classpath </li></ul><ul><ul><li>MySQL: </li></ul></ul><ul><ul><ul><li>mysql-connector-java-5.1.6-bin.jar </li></ul></ul></ul><ul><ul><li>Derby: </li></ul></ul><ul><ul><ul><li>derby.jar </li></ul></ul></ul>
  14. 14. Conectando com o banco <ul><li>Carregar a classe do driver </li></ul><ul><ul><li>Basta carregar o driver através do método Class.forName: Class.forName( &quot;com.mysql.jdbc.Driver&quot; ); Class.forName(&quot;org.apache.derby.jdbc.EmbeddedDriver&quot;); Class.forName(&quot;org.apache.derby.jdbc.ClientDriver&quot;); </li></ul></ul><ul><ul><li>No java 6 e com driver que implementa a API JDBC 4 não é mais necessário carregar a classe para que o driver seja registrado no DriverManager. </li></ul></ul><ul><ul><ul><li>Basta inserir o jar do driver no classpath e confiar no recurso de auto-discovery ou auto-loading de Driver JDBC. </li></ul></ul></ul><ul><ul><li>Como o DriverManager sabe se um jar possui um driver? </li></ul></ul><ul><ul><ul><li>O jar de um Driver possui o arquivo: META-INF/services/java.sql.Driver. Este arquivo armazena a classe do driver. No caso do mySQL será: com.mysql.jdbc.Driver. </li></ul></ul></ul>
  15. 15. Conectando com o banco <ul><li>Uso do driver </li></ul><ul><ul><li>O serviço que permite o uso do driver é delegado para um gerente de drivers: o DriverManager . </li></ul></ul><ul><li>Obtendo a conexão </li></ul><ul><ul><li>Através do DriverManager , usamos o método getConnection com uma url que indica que banco queremos acessar. </li></ul></ul><ul><ul><li>O padrão da url para acessar o mysql é: </li></ul></ul><ul><ul><ul><li>jdbc:mysql://host/banco </li></ul></ul></ul><ul><ul><ul><li>Exemplo: jdbc:mysql://localhost/teste </li></ul></ul></ul><ul><ul><li>Exemplos de URL para acessar o derby (JavaDB) é: </li></ul></ul><ul><ul><ul><li>jdbc:derby:teste; create=true </li></ul></ul></ul><ul><ul><ul><li>jdbc:derby://localhost/teste; create=true </li></ul></ul></ul>
  16. 16. URL <ul><li>A URL JDBC tem o seguinte formato: </li></ul><ul><ul><li>jdbc:subprotocolo:dsn </li></ul></ul><ul><ul><ul><li>Subprotocolo – identifica qual driver será instanciado. </li></ul></ul></ul><ul><ul><ul><li>dsn - nome que o subprotocolo usa para identificar um servidor e/ou base de dados. </li></ul></ul></ul><ul><li>Exemplos de URL: </li></ul><ul><ul><li>jdbc:odbc:nomedabasededados </li></ul></ul><ul><ul><li>jdbc:oracle:thin@localhost:nomedabasededados </li></ul></ul><ul><ul><li>jdbc:postgresql://localhost/nomedabasededados </li></ul></ul><ul><ul><li>jdbc:mysql://localhost/nomedabasededados </li></ul></ul><ul><ul><li>jdbc:derby:teste; create=true </li></ul></ul><ul><ul><li>jdbc:derby://localhost/teste; create=true </li></ul></ul>
  17. 17. Conectando com o banco - MySQL import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ExemplolJDBC { public static void main(String[] args) { try { Class. forName ( &quot;com.mysql.jdbc.Driver&quot; ); Connection con = DriverManager. getConnection ( &quot;jdbc:mysql://localhost/posbd4&quot; , &quot;root&quot; , &quot;root&quot; ); System. out .println( &quot;Conectado&quot; ); con.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } }
  18. 18. Conectando com o banco - JavaDB import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ExemplolJDBC { public static void main(String[] args) { try { Class. forName ( &quot;org.apache.derby.jdbc.EmbeddedDriver&quot; ); Connection con = DriverManager. getConnection ( &quot;jdbc:derby:posbd4; create=true&quot; ); System. out .println( &quot;Conectado&quot; ); con.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } }
  19. 19. Fábrica de conexões - MySQL import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ConnectionFactory { public static Connection getConnection() throws SQLException { try { Class. forName ( &quot;com.mysql.jdbc.Driver&quot; ); return DriverManager. getConnection ( &quot;jdbc:mysql://localhost/posbd4&quot; , &quot;root&quot; , &quot;root&quot; ); } catch (ClassNotFoundException e) { throw new SQLException(e.getMessage()); } } }
  20. 20. Fábrica de conexões - JavaDB import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ConnectionFactory { public static Connection getConnection() throws SQLException { try { Class. forName ( &quot;org.apache.derby.jdbc.EmbeddedDriver&quot; ); return DriverManager. getConnection ( &quot;jdbc:derby:posbd4; create=true&quot;) ; } catch (ClassNotFoundException e) { throw new SQLException(e.getMessage()); } } }
  21. 21. Comandos SQL <ul><li>Opção 1 </li></ul><ul><li>String sql = &quot;insert into contatos (nome,email,endereco) values ('&quot; + nome + &quot;', '&quot; + email + &quot;', '&quot; + endereco + &quot;')&quot; ; </li></ul><ul><li>Opção 2 </li></ul><ul><li>String sql = &quot;insert into contatos (nome,email,endereco) values (?,?,?)&quot; ; </li></ul><ul><li>Vantagens da opção 2: </li></ul><ul><ul><li>Melhor legibilidade </li></ul></ul><ul><ul><li>Evita SQL Injection (injeção de SQL) </li></ul></ul><ul><ul><li>Pode ser pre-compilada pelo SGBD </li></ul></ul>
  22. 22. Comandos SQL <ul><li>A execução de comandos SQL pode ser feita via: </li></ul><ul><ul><li>Statement </li></ul></ul><ul><ul><li>PreparedStatement </li></ul></ul><ul><ul><ul><li>Interface que estende a interface Statement. </li></ul></ul></ul><ul><ul><ul><li>Possibilita o uso de comandos pre-compilados pelo SGBD. </li></ul></ul></ul><ul><ul><ul><li>Torna-se mais rápido quando usado repetidamente </li></ul></ul></ul><ul><ul><ul><li>Os parâmetros são representados pelo símbolo “?”. </li></ul></ul></ul>
  23. 23. Executando um comando SQL // ... PreparedStatement stmt = con.prepareStatement( &quot;insert into contatos (nome,email,endereco) values (?,?,?)&quot; ); stmt.setString(1, &quot;Caelum&quot; ); stmt.setString(2, &quot;contato@caelum.com.br&quot; ); stmt.setString(3, &quot;R. Vergueiro 3185 cj57&quot; ); stmt.executeUpdate(); stmt.close(); // ... <ul><li>O índice dos parâmetros inicia por 1. </li></ul><ul><li>Para executar o comando podemos usar os métodos: </li></ul><ul><ul><li>boolean execute() - qualquer comando SQL </li></ul></ul><ul><ul><li>int executeUpdate() - DML (insert, update, delete) ou DDL. </li></ul></ul><ul><ul><li>ResultSet executeQuery() - Somente para consultas </li></ul></ul>
  24. 24. ResultSet <ul><li>Permite navegar por seus registros através do método next(). </li></ul>// ... PreparedStatement stmt = this .con.prepareStatement( &quot;select * from contatos&quot; ); ResultSet rs = stmt.executeQuery(); List<Contato> contatos = new ArrayList<Contato>(); while (rs.next()) { Contato contato = new Contato(); contato.setNome(rs.getString( &quot;nome&quot; )); contato.setEmail(rs.getString( &quot;email&quot; )); contato.setEndereco(rs.getString( &quot;endereco&quot; )); contatos.add(contato); } rs.close(); stmt.close(); return contatos;
  25. 25. Result Set <ul><li>O método executeQuery(), da interface Statement, retorna um objeto ResultSet. </li></ul><ul><ul><li>Cursor para as linhas de uma tabela </li></ul></ul><ul><ul><li>Pode-se navegar pelas linhas da tabela recuperar as informações armazenadas nas colunas </li></ul></ul><ul><li>Os métodos de navegação são: next(), previous(), absolute(), first() e last() </li></ul><ul><li>Métodos para obtenção de dados: getInt(), getString(), getDate()... </li></ul>
  26. 26. Recuperando dados de ResultSets <ul><li>Métodos getXXX </li></ul><ul><ul><li>Usam-se métodos dos ResultSets come çados por get </li></ul></ul><ul><ul><li>Recuperam um dado de acordo com o tipo </li></ul></ul><ul><ul><li>Como parâmetros podem ser usados a posição do campo (començando de 1) ou o nome do campo na tabela </li></ul></ul><ul><li>Ex: rs. getInt( “codigo” ) ou rs.getInt(1) rs. getString( “descricao” ) ou rs.getString(2) </li></ul>
  27. 27. Recuperando dados de ResultSets getBigDecimal() DECIMAL
  28. 28. Passos para uso do JDBC <ul><li>1. Carregar o driver 2. Estabelecer uma conexão com o BD 3. Criar uma declaração (PreparedStatement) e setar os parâmetros 4. Executar o comando ou consulta SQL 5. Processar o resultado 6. Fechar a conexão Em Java: 1. Class.forName(&quot;com.mysql.jdbc.Driver&quot;); 2. Connection con = DriverManager.getConnection (&quot;jdbc:mysql://localhost/teste&quot;, &quot;root&quot;,&quot;root&quot;); 3. PreparedStatement ps = con.prepareStatement(); 4.1. ps.executeUpdate(&quot;delete from Produtos&quot;); // ou 4.2. ResultSet rs = ps.executeQuery(&quot;select * from Produtos&quot;); 5. while(rs.next()) {       System.out.println(“Cód.: &quot; + rs.getString(1) + &quot; Desc: &quot; + rs.getString(2));     } 6. con.close(); </li></ul>
  29. 29. Fechando recursos <ul><li>Statements, PreparedStatements, ResultSets e Connections possuem um método close(). </li></ul><ul><li>Sempre que esses recursos não forem mais utilizados, é importante fechá-los. </li></ul><ul><li>Ao fechar a conexão, PreparedStatements e ResultSets que estão associados à conexão serão automaticamente fechados. </li></ul><ul><li>Exemplo de tratamento de exceções: </li></ul>try { // ... } catch (SQLException e) { // ... } finally { try { con.close(); } catch (SQLException e) { // ... } }
  30. 30. Transações <ul><li>Para permitir a criação de transações com mais de um comando, o modo de auto-commit deve ser desabilitado </li></ul><ul><li>O método setAutoCommit deve ser invocado no objeto do tipo Connection passando-se o valor false para ele </li></ul><ul><ul><li>con.setAutoCommit(false) ; </li></ul></ul><ul><li>Para realizar, respectivamente, o commit ou o rollback em uma transação utilize os seguintes métodos do objeto Connection: </li></ul><ul><ul><li>con.commit() </li></ul></ul><ul><ul><li>con.rollback() </li></ul></ul><ul><li>Nota : a pós terminar o uso de uma conexão, feche-a invocando o método close() da mesma </li></ul>
  31. 31. Fechando recursos com uso de transação // ... Connection conn = null; try { conn = ConnectionFactory.getConnection(); conn.setAutoCommit( false ); // ... conn.commit(); } catch (SQLException ex) { try { conn.rollback(); } catch (SQLException e) { // ... } } finally { try { conn.close(); } catch (SQLException ex){ // ... } }
  32. 32. DataSource <ul><li>Representa uma fábrica de conexões para o banco de dados físico </li></ul><ul><ul><li>Alternativa ao mais adequada ao uso DriverManager </li></ul></ul><ul><ul><li>Sua implementação é de responsabilidade do fornecedor do banco de dados </li></ul></ul><ul><ul><ul><li>Implementação Básica – cria conexões físicas da mesma forma do DriverManager </li></ul></ul></ul><ul><ul><ul><li>Implementação de Pool de Conexões – cria conexões que participarão de um pool (esta abordagem é usada em aplicações multi-camadas) </li></ul></ul></ul><ul><ul><ul><li>Implementação de Transações Distribuídas – semelhante à anterior exceto pelo fato de trabalhar com transações distribuídas </li></ul></ul></ul>
  33. 33. DataSource <ul><li>... </li></ul><ul><li>DataSource ds = new OracleConnectionPoolDataSource(url); </li></ul><ul><li>ds.getConnection(user, password); </li></ul><ul><li>... </li></ul>... Context initContext = new InitialContext(); Context envContext = (Context)initContext.lookup( &quot;java:/comp/env&quot; ); DataSource ds = (DataSource)envContext.lookup( &quot;jdbc/cefet&quot; ); conn = ds.getConnection()); ...
  34. 34. RowSet <ul><li>javax.sql.RowSet </li></ul><ul><ul><li>Interface disponível a partir do JDBC 3. </li></ul></ul><ul><ul><li>CachedRowSet pode ser usado em modo desconectado, permitindo acesso ao banco mesmo após o fechamento da conexão. Depois, pode ser retornado ao servidor para sincronização com a base de dados. </li></ul></ul><ul><ul><li>WebRowSet permite manipular dados de origem não-relacional (XML). </li></ul></ul><ul><ul><li>RowSets são uma boa representação de dados tabulares. </li></ul></ul>
  35. 35. Versões do JDBC <ul><li>Java 1.1 – JDBC 1.0 </li></ul><ul><li>Java 1.2 – JDBC 2.0 </li></ul><ul><ul><li>Interface DataSource para conexões gerenciadas por containers JEE; </li></ul></ul><ul><ul><li>Suporte a transações distribuídas; </li></ul></ul><ul><ul><li>Interface RowSet, que permite cache do resultado de consultas no cliente. </li></ul></ul><ul><li>Java 1.3 – JDBC 2.1 </li></ul><ul><ul><li>Atualizações em batch para envio de vários comandos SQL de uma só vez; </li></ul></ul><ul><ul><li>Suporte a resultados roláveis (scrollable) e atualizáveis para navegação livre por um ResultSet; </li></ul></ul><ul><ul><li>Atualização direta do registro corrente em um ResultSet, sem necessidade de enviar comandos de SQL update; </li></ul></ul><ul><ul><li>Mapeamento de tipos definidos pelo usuário. </li></ul></ul>
  36. 36. Versões do JDBC <ul><li>Java 1.4 – JDBC 3 </li></ul><ul><ul><li>Save points, que permitem rollback parcial de uma transação; </li></ul></ul><ul><ul><li>Parâmetros nomeados em stored procedures; </li></ul></ul><ul><ul><li>Forma padronizada de obter o valor de campos gerados automaticamente pelo banco (identity e autoincrement). </li></ul></ul>
  37. 37. Versões do JDBC <ul><li>Java 6 – JDBC 4 </li></ul><ul><ul><li>Auto-loading de driver JDBC; </li></ul></ul><ul><ul><li>Maior controle sobre pool de conexões e comandos; </li></ul></ul><ul><ul><li>Suporte ao tipo rowid (identif. Física de registros em alguns bancos como Oracle); </li></ul></ul><ul><ul><li>Suporte ao padrão SQL 2003; </li></ul></ul><ul><ul><li>Exceções mais específicas e não somente SQLException; </li></ul></ul><ul><ul><li>Manipulação de XML e suporte a extensões do SQL para dados XML. </li></ul></ul>
  38. 38. Versões do JDBC <ul><li>A proposta original do JDBC 4.0, incluído no Java 6, disponibilizava novas interfaces Query e DataSet apoiadas por anotações para mapear diretamente operações sobre o banco para métodos e atributos de classes. </li></ul><ul><li>Infelizmente esse recurso foi cancelado, pois sua implementação estava atrasada e a Sun não queria atrasar a release final do Java 6 que trouxe o JDBC 4. </li></ul><ul><li>Talvez esse recurso seja incluído no Java 7. </li></ul>
  39. 39. Versões do JDBC class User { int userID ; String name ; String department ; } interface MyQueries extends BaseQuery { @ Query(sql= &quot;select * from user&quot; ) DataSet getAllUsers(); @ Query(sql= &quot;select * from user where department= {department}&quot; ) DataSet getDepartmentUsers(String department); @ Update(sql= &quot;delete from user where name= {userName}&quot; ) int deleteUser(String userName); @ Update(sql= &quot;update user set department={department} where &quot; + &quot;name= {userName}&quot; ) int updateDeparment(String userName, String department); }
  40. 40. Versões do JDBC ... Connection c = myDataSource.getConnection(); MyQueries q = c.createQueryObject(MyQueries. class ); DataSet users = q.getAllUsers(); for (User u: users) { System.out.println( &quot;User's name is: &quot; + user.name; } ... ... Connection c = myDataSource.getConnection(); MyQueries q = c.createQueryObject(MyQueries. class ); DataSet users = q.create(); User user = new User(); user.setUserID(1); user.setName( &quot;Joe&quot; ); user.setDeparment( &quot;Accounting&quot; ); users.insert(user); ...
  41. 41. Referências <ul><li>Apostila da Caelum FJ-21 – Java para desenvolvimento Web – Capítulo 2 - JDBC </li></ul><ul><li>JDBC na Wikipedia: </li></ul><ul><ul><li>http://pt.wikipedia.org/wiki/JDBC </li></ul></ul><ul><li>Java com DB na Sun: </li></ul><ul><ul><li>http://java.sun.com/javase/technologies/database/ </li></ul></ul><ul><li>Encontrando Drivers JDBC </li></ul><ul><ul><li>http://developers.sun.com/product/jdbc/drivers </li></ul></ul><ul><li>Página sobre o uso de Java com MySQL </li></ul><ul><ul><li>http://dev.mysql.com/usingmysql/java/ </li></ul></ul>

×