Ao buscar uma lista de registros por meio de consultas, geralmente precisamos armazená-los em um objeto que permita o deslocamento para frente e para trás, atualizando conforme necessário. Este artigo ilustra essa técnica comumente necessária na programação de banco de dados com códigos explícitos e cenários de exemplo.
Sobre o ResultSet
O ResultSet é uma interface definida no java.sql pacote. Ele representa uma tabela de dados retornada por uma Instrução objeto. Uma Declaração O objeto é usado para executar consultas SQL no banco de dados. O objeto ResultSet mantém um cursor apontando para o registro atual na tabela do banco de dados. Como resultado, ele pode ser efetivamente usado para posicionar em diferentes linhas, para frente e para trás usando first() , anterior() , próximo() , e último() métodos de acordo com os requisitos. Inicialmente, o ResultSet objeto está posicionado em um local antes da primeira linha. Esta é a razão pela qual um ResultSet a travessia sempre começa da seguinte forma:
while(resultSet.next()) { // ... }
Observe que o ResultSet objeto é posicionado na primeira linha executando o next() ao entrar no loop, pois, como já mencionado, o ResultSet objeto está inicialmente localizado em uma posição imediatamente antes da primeira linha. Portanto, deve ser colocado pelo menos na primeira linha, por exemplo, para obter um registro válido. Pode ser considerado como um valor -1 em uma posição de matriz para a qual um ponteiro/índice está apontando. Ele deve primeiro ser realocado para pelo menos o local 0 para obter qualquer tipo de valor válido da matriz.
Agora, como mencionamos, podemos rolar pelos registros com a ajuda do ResultSet objeto. Mas, essa habilidade não vem por padrão. O comportamento padrão do ResultSet objeto é que ele não é atualizável e o cursor que ele possui na verdade se move em uma direção, apenas para frente. Isso significa que podemos iterar pelos registros apenas uma vez e apenas para frente. No entanto, existem maneiras de torná-lo flexível para que o ResultSet não é apenas atualizável, mas também rolável.
Nós os veremos em um minuto em dois programas separados.
Rolável ResultSet
Vamos primeiro fazer o ResultSet objeto rolável. Rolagem significa que uma vez que o ResultSet objeto foi criado, podemos percorrer os registros buscados em qualquer direção, para frente e para trás, como quisermos. Isso fornece a capacidade de ler o último registro, o primeiro registro, o próximo registro e o registro anterior.
package org.mano.example; import java.sql.*; public class App { static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost:3306/employees"; static final String USER = "root"; static final String PASS = "secret"; static final String SQL = "SELECT * FROM employees ORDER BY first_name"; public static void main( String[] args ) { Connection connection = null; ResultSet rs = null; try { Class.forName(JDBC_DRIVER); connection = DriverManager.getConnection (DB_URL, USER, PASS); System.out.println("n1. Connection established"); }catch(Exception ex) { ex.printStackTrace(); } try (PreparedStatement pstmt = connection.prepareStatement(SQL, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);){ System.out.println("n2. Executing SQL query..."); rs = pstmt.executeQuery(); System.out.println("n3. ResultSet object created successfully."); System.out.println("n4. Now some RecordSet scrolling starts..."); rs.first(); show(rs); rs.last(); show(rs); rs.previous(); rs.previous(); show(rs); rs.next(); show(rs); System.out.println("nn5. That's all. RecordSet scrolling ends."); }catch(SQLException ex){ ex.printStackTrace(); }finally{ try { connection.close(); }catch(SQLException ex){ } } } public static void show(ResultSet rs) throws SQLException{ System.out.printf ("n--------------------------------"+ "-------------------------------------"); System.out.printf("n%7d | %10s | %10s | %s | %s | %s ",rs.getLong("emp_no"), rs.getString("first_name"), rs.getString("last_name"), rs.getDate("birth_date").toString(), rs.getDate("hire_date"), rs.getString("gender")); System.out.printf ("n---------------------------------"+ "------------------------------------"); } }
Saída
- Conexão estabelecida.
- Executando consulta SQL…
- Objeto ResultSet criado com sucesso.
- Agora, alguma rolagem do RecordSet começa…
------------------------------------------------------------- 497615 | Aamer | McDermid | 1954-11-18 | 1985-04-24 | M ------------------------------------------------------------- ------------------------------------------------------------- 484995 | Zvonko | Lakshmanan | 1964-11-04 | 1992-12-04 | M ------------------------------------------------------------- ------------------------------------------------------------- 482000 | Zvonko | Cannata | 1960-11-23 | 1986-08-13 | M ------------------------------------------------------------- ------------------------------------------------------------- 483497 | Zvonko | Pollacia | 1961-12-26 | 1985-08-01 | M -------------------------------------------------------------
- Isso é tudo. A rolagem do RecordSet termina.
Observe que o ResultSet rolável objeto é o resultado da execução do executeQuery() método obtido através da instância de Statement ou PreparedStatement . O tipo de ResultSet objeto que gostamos de criar deve ser declarado explicitamente para a Instrução objeto por meio de constantes de tipo de rolagem definidas.
- ResultSet.TYPE_FORWARD_ONLY: Este é o tipo padrão.
- ResultSet.TYPE_SCROLL_INSENSITIVE: Ativa o movimento para frente e para trás, mas é insensível ao ResultSet atualizações.
- ResultSet.TYPE_SCROLL_SENSITIVE: Ativa o movimento para frente e para trás, mas é sensível ao ResultSet atualizações.
Existem outras constantes usadas, como CONCUR_READ_ONLY , o que significa que o ResultSet não é atualizável. Existe outra constante, CONCUR_UPDATABLE , que significa o oposto, significando o ResultSet é atualizável.
ResultSet atualizável
Criando um ResultSet atualizável significa que o registro para o qual ele aponta não é apenas percorrível, mas também atualizável. As alterações serão mantidas imediatamente no banco de dados e refletidas pelo ResultSet objeto em tempo real.
package org.mano.example; import java.sql.*; public class App { static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost:3306/employees"; static final String USER = "root"; static final String PASS = "secret"; static final String SQL = "SELECT * FROM employees WHERE emp_no = ?"; public static void main( String[] args ) { Connection connection = null; ResultSet rs = null; long emp_no = 484995; try { Class.forName(JDBC_DRIVER); connection = DriverManager.getConnection (DB_URL, USER, PASS); System.out.println("n1. Connection established"); }catch(Exception ex) { ex.printStackTrace(); } try(PreparedStatement pstmt = connection.prepareStatement(SQL, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);){ pstmt.setLong(1,emp_no); System.out.println("n2. Executing SQL query..."); rs = pstmt.executeQuery(); System.out.println("n3. ResultSet object created successfully."); while(rs.next()){ show(rs); String fname = rs.getString("first_name"); System.out.println("n4. Updating name "+fname+" to Subham"); rs.updateString("first_name", "Subham"); rs.updateRow(); } System.out.println("nn5. Record updated. See below."); rs.previous(); show(rs); }catch(SQLException ex){ ex.printStackTrace(); }finally{ try { rs.close(); connection.close(); }catch(SQLException ex){ } } } public static void show(ResultSet rs) throwsSQLException{ System.out.printf ("n--------------------------------"+ "-------------------------------------"); System.out.printf("n%7d | %10s | %10s | %s | %s | %s ",rs.getLong("emp_no"), rs.getString("first_name"), rs.getString("last_name"), rs.getDate("birth_date").toString(), rs.getDate("hire_date"), rs.getString("gender")); System.out.printf ("n---------------------------------"+ "------------------------------------"); } }
O ResultSet atualizável é particularmente útil quando queremos atualizar certos valores depois de fazer alguma comparação percorrendo para frente e para trás os registros buscados. O processo de criação é semelhante ao programa anterior, mas o ResultSet constantes usadas aqui são TYPE_SCROLL_SENSITIVE e CONCUR_UPDATABLE .
Conclusão
Ao contrário do comportamento padrão do ResultSet, ele capacita o objeto a ter maior flexibilidade. Essa funcionalidade pode ser aproveitada pelo aplicativo para não apenas percorrer os registros, mas também torná-los atualizáveis para que possam fornecer um serviço melhor. Embora o comportamento padrão de um conjunto de resultados pareça bastante ineficiente em comparação com o ResultSet rolável , tem seu próprio uso e, portanto, é insubstituível.