JDBC: Fechar Connection antes de pegar resultados. Pode?

Olá:

Segue o código:

public class Teste {

	public static void main(String[] args) throws Exception {
		Class.forName("org.postgresql.Driver");
		Statement stmt = null;
		Connection conn = null;
		ResultSet rs = null;
		try {
			try {
				conn = DriverManager.getConnection("jdbc:postgresql:base", "Rafael U. C. Afonso", "");
				stmt = conn.createStatement();
				rs = stmt.executeQuery("SELECT * FROM cliente");
			} finally {
				conn.close();
			}
			while(rs.next()) {
				System.out.println(rs.getInt(1) + "-" + rs.getString(2));
			}
		} finally {
			stmt.close();
			rs.close();
		}
	}
}

Como podem ver, estou fechando a conexão antes de pegar os resultados do ResultSet. O programa roda normalmente. Se eu colocar stmt.close() dentro do primeiro finally, uma exceção é disparada.
:?: A minha dúvida é: Isto está certo? Se não, por quê? Me convençam que isto está errado.

Grato,

La vai um chute:
Isso ocorre por que o ResultSet é aberto como desconectado…

O ResultSet é um cursor criado em memória e depois de criado, não precisa mais da conexão com o banco.

não é não, o resultset não é um cursos em memoria, até por isto, que cada driver tem uma implementação de ResultSet
ele vai fazendo o fetch do banco a cada next (bom, isto depende de configurações, mas a ideia é esta)

Vc não deve fechar o connection antes do ResultSet! Como o urubatan disse, fica um cursor ativo para trazer os registros sob-demanda.

[]s, Welington B. Souza

Vai aí o seu código um pouco “melhorado” para se trabalhar com JDBC.

[code]import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Teste {

public static void main(String[] args) {
	Statement stmt = null;
	Connection conn = null;
	ResultSet rs = null;
	try {
		Class.forName("org.postgresql.Driver");
		conn = DriverManager.getConnection("jdbc:postgresql:base", 
			"Rafael U. C. Afonso", "");
		stmt = conn.createStatement();
		rs = stmt.executeQuery("SELECT * FROM cliente");
		while (rs.next()) {
			System.out.println(rs.getInt(1) + "-" + rs.getString(2));
		}
	}
	catch (ClassNotFoundException e1) {
		System.out.println("Erro ao Carregar o JDBC Driver: " + 
			e1.getMessage());
	}
	catch (SQLException e2) {
		System.out.println(e2.getMessage());
	}
	finally {
		closeResources(conn, stmt, rs);
	}
}

private static void closeResources(Connection conn, 
	Statement stmt, ResultSet rs) {
		
	if (rs != null) {
		try {
			rs.close();
		}
		catch (SQLException e) {
			System.out.println(e.getMessage());
		}
	}
	if (stmt != null) {
		try {
			stmt.close();
		}
		catch (SQLException e) {
			System.out.println(e.getMessage());
		}
	}
	if (conn != null) {
		try {
			conn.close();
		}
		catch (SQLException e) {
			System.out.println(e.getMessage());
		}
	}	
}

}[/code]

[]s, Welington B. Souza

Olá:

Urubatan: De fato pensei melhor e também acho que isso deve depender da implementação de cada driver. Mesmo se estes drivers forem para o mesmo BD.
Welington: Já estou usando um método parecido com o seu no meu projeto.
Eu gostaria de ter um jeito de me livrar das classes que não vou usar mais (como o Connection e o Statement) depois de executar a query para otimizar recursos. Entretanto parece que vou ter que carregar o trio Connection-PrepaedStatement-ResultSet até o fim da minha transação. Como dizem, a otimização precoce é a raiz de todo o mal. :wink:

Grato,