O JDBC (Java Database Connectivity) que é uma biblioteca existente dentro da especificação Java que contém um conjunto de interfaces e classes que estão dentro do pacote java.sql que permitem a interação e conectividade com banco de dados pela aplicação, permitindo desenvolver queries específicas para um determinado banco, por exemplo escrever uma estrutura de query com o dialeto do MySQL ou do Oracle.

Porque usar o JDBC

Quando utilizamos aplicações, sejam elas empresariais ou comerciais, é importante armazenar ou recuperar as informações geradas. Para isso o JDBC é eficaz para permitir a interação e estabelecer conexão com o banco de dados de forma eficiente. Além disso, com essa biblioteca poderemos executar operações SQL como: Select (consultar), Update (atualizar), Delete (excluir) e Insert (incluir), além de permitir implementar objetos mais complexos como stored procedures, views, funções.

Componentes do JDBC

A biblioteca provê muitos métodos e interfaces para facilitar a comunicação com os bancos de dados, divididos em dois pacotes, um específico para plataforma Java SE e outro para a Java EE:

  • java.sql => Este pacote contém classes e métodos para acesso a dados e processamento em um banco de dados relacional, este incluído em Java Standard Edition (Java SE);
  • javax.sql = > Este pacote amplia a funcionalidade do pacote java.sql implementando outras interfaces utilizadas em aplicações do lado do servidor. Este segue especificações da Java Enterprise Edition (Java EE).

Para que a aplicação possa se conectar ao banco de dados é necessário adicionarmos o driver que fará essa implementação, chamado de JDBC Driver manager (Gerenciador de driver JDBC). Com ele é possível acessar um banco de dados específico, isso significa que para acessar um banco Oracle, por exemplo, teremos que configurar um driver para esse banco, e assim para os demais.

Na Figura 1, temos uma representação da estrutura de uma aplicação utilizando JDBC.

Fluxo do JDBC em uma aplicação Java
Figura 1. Fluxo do JDBC em uma aplicação Java

Podemos descrever esse fluxo da seguinte forma:

  • Na primeira camada temos a aplicação Java, que pode ser desktop ou web, por exemplo;
  • Na segunda camada temos a API do JDBC, que contém classes e métodos para permitir a escrita de queries ou chamar alguma stored procedure;
  • Na terceira camada temos o JDBC Driver Manager, que contém as classes e métodos utilizados para configurar a aplicação para conectar-se com o banco;
  • Na quarta camada e última temos o driver específico para cada banco de dados (SQL Server, Oracle, MySQL etc.) onde deveremos implementar um arquivo de biblioteca do tipo .jar.

Como implementar no projeto

Para implementarmos esse driver em nossos projetos existem várias formas. A mais comum atualmente é adicionar em um projeto Maven, no arquivo pom.xml, a dependência para realizar o download da biblioteca.

No Código 1, temos um exemplo para incluir no arquivo de dependência o driver para o banco MySQL.


<!--   https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.33</version>
</dependency>
Código 1. Dependência que deverá ser adicionada no arquivo pom.xml utilizado em projetos Maven

Em seguida, teremos que realizar duas outras implementações: fazer uma conexão com o banco de dados e fazer uma consulta em uma tabela do projeto.


package br.com.exemplo.conexao;
   
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
 import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
 import javax.sql.DataSource;
   
 public class Conexao {
   private static Connection conexao = null;
   public static Connection getConnection()
   throws   InstantiationException, IllegalAccessException, ClassNotFoundException,   SQLException, NamingException {
   
     String url = "jdbc:mysql://localhost:3306/bancoExemplo";
     String user = "testeExemplo";
     String password = "exemplo";
     Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
     conexao  = DriverManager.getConnection(url, user,   password);
     return conexao;
 }
 public static void close (){
   try {       
    conexao.close();
   } catch (SQLException e) {
      e.printStackTrace();
   }
  }
 }
Código 2. Exemplo de uma classe que faz a conexão com o banco de dados

No Código 2, temos um exemplo de classe que faz a conexão com o MySQL. Nele criamos um método chamado getConnection, que contém a definição de variáveis que utilizamos para configurar o acesso a base de dados, além do pacote com.mysql.cj.jdbc.Driver, que é a biblioteca utilizada por esse banco. Detalharemos abaixo o que essas variáveis e objetos significam:

  • private static Connection conexao = null => Instanciando objeto;
  • url => é a string de conexão que contém o servidor do banco, porta que esse banco utiliza e nome da base de dados pelo se conectará. Sempre é iniciada com jdbc:<<nome do driver>>. No caso do nosso exemplo seria mysql;
  • user => é o usuário que faz o acesso ao banco de dados;
  • password => é a senha utilizada para acessar o banco;
  • Class.forName => é a instância que será criada a partir do driver do MySQL;
  • conexao => receberá do método getConnection da classe DriverManager as informações para acesso ao banco que nos permitirá executar as queries.

Além disso, temos outro método chamado close que deveremos executar ao final de uma execução de query para encerrar uma conexão de banco aberta sempre que chamamos o método getConnection. É importante sempre finalizar as conexões de banco, pois geralmente problemas de lentidão são devido ao excesso de conexões que foram abertas e esquecidas.


package br.com.exemplo.BD;
   
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import javax.naming.NamingException;
 import br.com.exemplo.conexao.Conexao;
 import br.com.exemplo.modelo.Grupo;
 
  public class GrupoBD {
    public Grupo   obterGrupo(Integer idGrupo)  {
      Grupo grupo = new Grupo();
         
      try {
        Connection conn =   Conexao.getConnection();
        PreparedStatement st_grupo =   conn.prepareStatement("SELECT   id_grupo, nmGrupo FROM grupo WHERE id_grupo = ? ");
        st_grupo.setInt(1, idGrupo);
        ResultSet rsGrupo =   st_grupo.executeQuery();
   
        if (rsGrupo.first()) {
   
          grupo.setIdGrupo(rsGrupo.getInt("id_grupo"));
          grupo.setNmGrupo(rsGrupo.getString("nmGrupo"));
        }
                     
   
      } catch (SQLException |   InstantiationException | IllegalAccessException | ClassNotFoundException |   NamingException e) {
         e.printStackTrace();
      } finally {
         try {
           if(rsGrupo   != null) rsGrupo.close();
           if(st_grupo != null)   st_grupo.close();
           if(conn   != null) conn.close();       
        } catch   (SQLException e) {
           throw new SystemException(e.getMessage());
        }
      }  
      return   grupo;        
   }
 }
Código 3. Exemplo de uma classe que faz uma consulta em uma tabela

No Código 3, exemplificamos a classe grupoDB com o método em que executamos um select para obter os dados da tabela grupo.

Neste caso escrevemos essa estrutura para obter essas informações através de um resultset, que será atribuído ao objeto grupo que retornará para a aplicação. Detalharemos a seguir as linhas do código para melhor entendimento:

  • Grupo grupo = new Grupo() => Instanciando objeto;
  • Connection conn = Conexao.getConnection() => estamos abrindo a conexão criada no Código 2;
  • PreparedStatement st_grupo = conn.prepareStatement("SELECT id_grupo, nmGrupo FROM grupo WHERE id_grupo = ? ") => permite utilizarmos a query que será executada. Quando queremos utilizar um parâmetro colocamos ? para informar que o valor da condição virá de uma variável;
  • st_grupo.setInt(1, idGrupo) => informaremos ao PreparedStatement o parâmetro que será substituído no "?" ao executar a query;
  • ResultSet rsGrupo = st_grupo.executeQuery() => será executada a query que será retornada para um tipo ResultSet para obter o resultado da consulta;
  • No bloco abaixo obtemos o retorno da nossa consulta utilizando rsGrupo.first(), pois queremos obter a primeira linha encontrada. Como podemos observar, temos duas colunas (id_grupo e nmGrupo) para cada linha correspondente a um atributo do objeto grupo:
    
    if   (rsGrupo.first()) {
      grupo.setIdGrupo(rsGrupo.getInt("id_grupo"));
      grupo.setNmGrupo(rsGrupo.getString("nmGrupo"));
    }
    
  • Temos o bloco importante no Código 3 do finally, onde finalizamos todos os objetos abertos durante a execução da query, evitando manter esses objetos abertos que com o tempo degradarão a performance da aplicação, principalmente a conexão ao banco de dados:
    
    } finally {
      try {
        if(rsGrupo != null) rsGrupo.close();
        if(st_grupo   != null) st_grupo.close();
        if(conn   != null) conn.close();      
      } catch   (SQLException e) {
        throw new   SystemException(e.getMessage());
      }
    }
    

Conclusão

O JDBC é uma implementação muito importante para utilizarmos em um projeto Java, pois permite conectar com diversos bancos de dados existentes no mercado, além de possuir um conjunto de interfaces e métodos para executarmos queries utilizando o dialeto SQL que cada banco entende, além de outros objetos de banco como stored procedures, views ou funções. Neste artigo fizemos uma pequena introdução do que essa biblioteca tem a oferecer.