Conceitos Fundamentais de JDBC e Práticas Avançadas

Drivers de Banco de Dados

Definição de Driver de Banco

Um driver de banco de dados consiste em um arquivo JAR fornecido pelo fbaricante do banco para permitir a interação com o sistema de gerenciamento de banco de dados.

Visão Geral do JDBC

O que é JDBC

JDBC (Java Data base Connectivity) representa uma especificação da Sun Microsystems que estabelece interfaces padronizadas para acesso a bancos de dados relacionais. Como diferentes fornecedores implementam seus próprios drivers seguindo estas interfaces, os desenvolvedores precisam aprender apenas um conjunto único de APIs para trabalhar com diversos bancos de dados.

Pacotes JDBC

As funcionalidades principais do JDBC estão contidas nos pacotes java.sql e javax.sql, que fazem parte do Java SE. Para desenvolver aplicações com banco de dados, é necessário incluir também o driver específico do banco que será utilizado.

Fluxo Básico de Operações JDBC

O processo padrão para execução de operações com JDBC envolve seis etapas principais:

  1. Registro do driver do banco
  2. Estabelecimento da conexão
  3. Criação do objeto de statement
  4. Execução da consulta SQL
  5. Processamento dos resultados
  6. Liberação dos recursos

Connection conexao = null;
Statement declaracao = null;
ResultSet resultado = null;

try {
    // Registrar driver
    Class.forName("com.mysql.jdbc.Driver");
    
    // Estabelecer conexão
    conexao = DriverManager.getConnection(
        "jdbc:mysql://localhost:3306/empresa", "admin", "senha123");
    
    // Criar statement
    declaracao = conexao.createStatement();
    
    // Executar consulta
    resultado = declaracao.executeQuery("SELECT id, nome FROM funcionarios");
    
    // Processar resultados
    while(resultado.next()) {
        int id = resultado.getInt("id");
        String nome = resultado.getString("nome");
        System.out.println("ID: " + id + ", Nome: " + nome);
    }
} catch (Exception ex) {
    ex.printStackTrace();
} finally {
    // Fechar recursos
    try {
        if(resultado != null) resultado.close();
        if(declaracao != null) declaracao.close();
        if(conexao != null) conexao.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

Operações CRUD - Exemplo de Exclusão

Configuração via Arquivo de Propriedades

Crie um arquivo config.properties com:


driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost/empresa
usuario=admin
senha=senha123

Classe Utilitária para Conexão


public class GerenciadorConexao {
    private static Properties config = new Properties();
    
    static {
        try {
            InputStream entrada = GerenciadorConexao.class
                .getClassLoader().getResourceAsStream("config.properties");
            config.load(entrada);
        } catch (IOException e) {
            throw new RuntimeException("Erro ao carregar configurações", e);
        }
    }
    
    public static Connection obterConexao() throws SQLException {
        String driver = config.getProperty("driver");
        String url = config.getProperty("url");
        String usuario = config.getProperty("usuario");
        String senha = config.getProperty("senha");
        
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            throw new SQLException("Driver não encontrado", e);
        }
        
        return DriverManager.getConnection(url, usuario, senha);
    }
}

Implementação da Exclusão


Connection conexao = null;
Statement declaracao = null;

try {
    conexao = GerenciadorConexao.obterConexao();
    declaracao = conexao.createStatement();
    int linhasAfetadas = declaracao.executeUpdate(
        "DELETE FROM produtos WHERE categoria = 'obsoletos'");
    System.out.println(linhasAfetadas + " registros removidos");
} catch (SQLException e) {
    throw new RuntimeException("Erro na exclusão", e);
} finally {
    // Fechar recursos
}

Proteção contra SQL Injection

O Problema

O ataque por injeção de SQL ocorre quando entradas do usuário contendo comandos SQL maliciosos são concatenadas diretamente nas consultas, alterando seu comportamento original.

Solução com PreparedStatement

O PreparedStatement utiliza compilação prévia, onde a estrutura da consulta é definida entecipadamente e os parâmetros são tratados como valores, não como parte do código SQL.


public void inserirCliente(Cliente cliente) {
    Connection conexao = null;
    PreparedStatement ps = null;
    
    try {
        conexao = GerenciadorConexao.obterConexao();
        ps = conexao.prepareStatement(
            "INSERT INTO clientes (nome, email, telefone) VALUES (?, ?, ?)");
        
        ps.setString(1, cliente.getNome());
        ps.setString(2, cliente.getEmail());
        ps.setString(3, cliente.getTelefone());
        
        ps.executeUpdate();
    } catch (SQLException e) {
        throw new RuntimeException("Erro ao inserir cliente", e);
    } finally {
        // Liberar recursos
    }
}

Processamento em Lote

Utilizando Statement


Connection conexao = GerenciadorConexao.obterConexao();
Statement stmt = conexao.createStatement();

stmt.addBatch("INSERT INTO logs (mensagem) VALUES ('Operação 1')");
stmt.addBatch("UPDATE contadores SET valor = valor + 1");
stmt.addBatch("DELETE FROM temporarios WHERE expirado = true");

int[] resultados = stmt.executeBatch();

Utilizando PreparedStatement


String sql = "INSERT INTO pedidos (cliente_id, valor) VALUES (?, ?)";
PreparedStatement ps = conexao.prepareStatement(sql);

for(int i = 0; i < 1000; i++) {
    ps.setInt(1, i + 1000);
    ps.setDouble(2, Math.random() * 1000);
    ps.addBatch();
    
    if(i % 100 == 0) {
        ps.executeBatch();
        ps.clearBatch();
    }
}

ps.executeBatch();

Pool de Conexões

Configuração do C3P0

Arquivo c3p0-config.xml:


<c3p0-config>
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost/empresa</property>
        <property name="user">admin</property>
        <property name="password">senha123</property>
        <property name="initialPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </default-config>
</c3p0-config>

Uso do Pool


ComboPooledDataSource pool = new ComboPooledDataSource();
Connection conexao = pool.getConnection();

// Utilizar conexão normalmente
// ...

conexao.close(); // Devolve a conexão ao pool

Controle de Transações

Gerenciamento Manual


Connection conexao = null;

try {
    conexao = GerenciadorConexao.obterConexao();
    conexao.setAutoCommit(false);
    
    // Executar múltiplas operações
    executarOperacao1(conexao);
    executarOperacao2(conexao);
    
    conexao.commit();
} catch (SQLException e) {
    if(conexao != null) {
        try {
            conexao.rollback();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
    throw new RuntimeException("Transação falhou", e);
} finally {
    // Restaurar auto-commit e fechar conexão
}

Pontos de Salvamento (Savepoints)


conexao.setAutoCommit(false);

Savepoint ponto1 = conexao.setSavepoint("PONTO_1");
// Executar algumas operações

Savepoint ponto2 = conexao.setSavepoint("PONTO_2");
// Executar mais operações

// Reverter até ponto específico
conexao.rollback(ponto1);

conexao.commit();

Tags: jdbc java MySQL PreparedStatement sql-injection

Publicado em 8-8 06:10