W3docs

Conexão JDBC em Java

Abra e gerencie conexões com bancos de dados em Java com a interface Connection — abrir, fechar e configurar.

Uma Connection é uma sessão ativa com o banco de dados. É o objeto que você recebe do DriverManager (ou de um DataSource), e é a fábrica para tudo o mais — statements, transações, savepoints, metadados. Uma conexão também é um recurso escasso e custoso: cada uma aberta ocupa um socket e uma sessão no servidor, portanto a regra fundamental é abrir tarde, fechar rapidamente.

Este capítulo aborda como construir uma URL de conexão, as três formas de abrir uma Connection, por que try-with-resources é indispensável, as configurações de sessão que você pode ajustar e os erros que você encontrará quando algo estiver mal configurado. Pressupõe-se que você já carregou um driver — consulte JDBC Drivers e a Introdução ao JDBC para uma visão mais ampla.

A URL de conexão

Tudo o que o DriverManager precisa para encontrar e acessar um banco de dados é codificado na URL:

jdbc:<subprotocol>://<host>:<port>/<database>?<key=value&...>

Por exemplo, jdbc:postgresql://db.internal:5432/shop?ssl=true. O prefixo jdbc: é obrigatório; o subprotocolo seleciona o driver; o restante é específico do fornecedor, mas convencionalmente inclui host, porta, banco de dados e uma query string com opções de configuração. Algumas URLs reais para reconhecer:

Banco de DadosExemplo de URL
PostgreSQLjdbc:postgresql://localhost:5432/shop
MySQLjdbc:mysql://localhost:3306/shop?useSSL=true
H2 (em memória)jdbc:h2:mem:testdb
SQLite (arquivo)jdbc:sqlite:/data/shop.db

O subprotocolo (postgresql, mysql, h2, sqlite) é como o DriverManager decide qual driver registrado deve tratar a URL, portanto acertá-lo é o que diz ao JDBC qual banco de dados você quer dizer.

Três formas de abrir uma conexão

// 1. URL with credentials as arguments
Connection a = DriverManager.getConnection(url, "app", "secret");

// 2. URL with a Properties bag (user, password, plus driver-specific keys)
Properties props = new Properties();
props.setProperty("user", "app");
props.setProperty("password", "secret");
props.setProperty("connectTimeout", "10");
Connection b = DriverManager.getConnection(url, props);

// 3. From a pooled DataSource (preferred for applications)
Connection c = dataSource.getConnection();

DriverManager vs. DataSource

DriverManager.getConnection(...) abre uma conexão física completamente nova a cada vez e a encerra quando você a fecha. Esse handshake — consulta DNS, TCP, TLS, autenticação — custa dezenas de milissegundos, o que é aceitável para um script, mas ruinoso para um servidor que trata muitas requisições.

Um DataSource apoiado por um pool de conexões (HikariCP, Apache DBCP ou o que o servidor de aplicação fornece) mantém um conjunto de conexões físicas abertas e as distribui. Chamar getConnection() empresta uma; chamar close() a devolve ao pool em vez de encerrá-la de verdade. Para qualquer aplicação de longa duração, prefira um DataSource com pool; recorra ao DriverManager apenas em pequenas ferramentas, testes e exemplos.

Sempre feche — use try-with-resources

Connection, Statement e ResultSet implementam AutoCloseable. Declará-los no cabeçalho de um try-with-resources garante que sejam fechados em ordem inversa mesmo que uma exceção seja lançada — o hábito mais importante no JDBC:

try (Connection conn = DriverManager.getConnection(url, "app", "secret")) {
  // use conn...
} // conn.close() runs here automatically, even on exception

Vazar conexões (esquecer de fechar) esgota o pool e eventualmente trava toda a aplicação — uma clássica falha em produção. Note que abrir uma Connection lança uma SQLException verificada, portanto a chamada sempre fica dentro de um try (ou em um método que declara throws SQLException).

Uma vez que você tenha uma conexão, pode usá-la para criar Statements e PreparedStatements — e eles devem ficar dentro do mesmo cabeçalho try-with-resources para que sejam fechados antes da conexão:

try (Connection conn = dataSource.getConnection();
     PreparedStatement ps = conn.prepareStatement("SELECT name FROM users WHERE id = ?")) {
  ps.setInt(1, 42);
  // ...read the ResultSet...
} // ps closes first, then conn — reverse declaration order

Configurando uma conexão

Uma vez aberta, uma conexão carrega configurações de nível de sessão:

MétodoO que faz
setAutoCommit(false)Inicia uma transação manual; você então chama commit() ou rollback() manualmente. Consulte JDBC Transactions.
setTransactionIsolation(...)Define um nível de isolamento (por exemplo, TRANSACTION_READ_COMMITTED).
setReadOnly(true)Uma dica de que a conexão não realiza escritas; alguns drivers a otimizam para isso.
setSchema(...) / setCatalog(...)Seleciona o namespace contra o qual as consultas são executadas.
isValid(timeout)Retorna true se a conexão ainda está ativa; pools usam isso para descartar conexões mortas.

Essas configurações são por sessão, portanto são redefinidas quando uma conexão real é fechada — mas com um pool, uma conexão emprestada pode ainda carregar configurações deixadas por um usuário anterior. É por isso que os pools redefinem autoCommit e isolamento ao devolver, e por que você deve definir o que precisa em vez de assumir os padrões.

Erros comuns de conexão

Quando uma conexão falha, você quase sempre recebe uma SQLException; a mensagem indica qual camada falhou:

  • No suitable driver found for ... — a classe do driver nunca foi carregada, ou o subprotocolo da URL está com erro de digitação, de modo que nenhum driver registrado a reivindica. Corrija a dependência ou a URL (consulte JDBC Drivers).
  • Connection refused — nada está ouvindo nesse host/porta: o banco de dados está inativo ou o host/porta na URL está errado.
  • Authentication / password authentication faileduser ou password incorretos, ou o usuário não tem direitos sobre esse banco de dados.
  • Connection timeout — o host está inacessível (firewall, rede incorreta). Defina connectTimeout para que a chamada falhe rapidamente em vez de travar.

Um exemplo prático: a anatomia de uma URL de conexão

Este programa desmonta uma URL JDBC realista em seus componentes e constrói o objeto Properties que você passaria junto com ela — as duas entradas que getConnection precisa — sem exigir um banco de dados ativo.

java— editable, runs on the server

O que aprender com a execução:

  • A URL não é opaca — é dado estruturado. getConnection analisa exatamente estas partes: o subprotocolo escolhe o driver, e o host/porta/banco de dados dizem a esse driver onde conectar. Ler uma URL em voz alta é a forma mais rápida de depurar erros de "banco de dados errado".
  • A query string (?ssl=true&applicationName=reports) carrega opções específicas do driver. As mesmas configurações podem estar na URL ou no objeto Properties — ambas chegam ao driver, e você os mistura a seu gosto.
  • As credenciais pertencem ao Properties (ou à configuração do DataSource), não codificadas diretamente na string de URL que você registra. O exemplo mascara a senha na saída exatamente por esse motivo — nunca registre credenciais em log.
  • connectTimeout é uma propriedade real do driver PostgreSQL. O ajuste fica nesses pares chave/valor, razão pela qual você raramente precisa criar subclasses: é a configuração, não o código, que molda uma conexão.
  • Isso foi executado sem um banco de dados porque construir as entradas para getConnection é puro trabalho com strings. A parte custosa — o socket e a sessão no servidor — só acontece na chamada de getConnection em si, razão pela qual você a adia e a fecha rapidamente.

Prática

Prática
Por que uma Connection JDBC quase sempre deve ser adquirida dentro de um try-with-resources?
Por que uma Connection JDBC quase sempre deve ser adquirida dentro de um try-with-resources?
Was this page helpful?