Às vezes, as consultas de aplicativos a um banco de dados retornam um grande número de linhas. Embora os dados obtidos sejam armazenados em cache no ResultSet objeto, muitas vezes é grande demais para trabalhar com eles. Como resultado, devemos ser capazes de filtrá-los em diferentes conjuntos de dados para limitar as linhas visíveis. Este artigo descreve o aspecto de filtragem do JDBC RowSet com exemplos apropriados.
Uma visão geral do RowSet
Conjunto de linhas é uma interface que complementa o modelo de componente JDBC API for JavaBeans. Ele fornece um conjunto de propriedades que permite que sua instância seja configurada para se conectar a uma fonte de dados JDBC. Um RowSet instância é usada principalmente para recuperar dados da fonte de dados. Os métodos setter dessa interface são utilizados para preencher os parâmetros da propriedade command de uma consulta SQL, que então é utilizada para buscar registros do banco de dados relacional. Porque RowSet adere ao modelo de componente JavaBean, ele suporta eventos JavaBean. Esses eventos são usados para notificar outros componentes sobre eventos, como uma alteração de valor em um conjunto de linhas. Porque o RowSet interface é projetada como uma camada acima do driver JDBC, é aberta à implementação personalizada. Essa liberdade capacita o fornecedor a fabricar sua própria efetuação ajustada e enviá-la com o produto JDBC.
O FilteredRowSet
O FilteredRowSet é uma extensão de interface do RowSet família. Existe uma implementação de referência desta interface, chamada FilteredRowSetImpl aula. Para fornecer uma implementação personalizada do FilteredRowSet interface, pode-se estender o FilteredRowSetImpl class ou use o FilteredRowSet interface conforme sua exigência. Em algumas ocasiões, precisamos aplicar alguma forma de filtragem no conteúdo que RowSet busca. Uma solução possível simples é fornecer uma linguagem de consulta para todos os RowSet implementações. Mas essa não é uma abordagem viável porque RowSet é construído com a ideia de um componente leve desconectado. Isso tornaria o objeto pesado e iria contra seu princípio de design. Precisamos de uma abordagem que atenda à necessidade, mas que não injete uma linguagem de consulta pesada junto com a lógica de processamento de filtragem. O JDBC FilteredRowSet implementação padrão estende RowSet através das subinterfaces como CachedRowSet e WebRowSet respectivamente. O FilteredRowSet pode manipular o cursor através do conjunto de métodos de manipulação de cursor protegidos fornecidos pelo CachedRowSet interface. Esses métodos podem ser substituídos de acordo com os requisitos e ajudam na filtragem de RowSet contente.
Um exemplo rápido
Aqui está um exemplo para ilustrar como FilteredRowSet é usado para armazenar o conteúdo retornado pela consulta disparada ao banco de dados. O resultado da consulta é filtrado de acordo com a configuração aplicada ao FilteredRowset implementação. Isso define o conteúdo visível ou as linhas que nos interessam a partir do resultado retornado pela consulta. No exemplo a seguir, criamos uma classe de filtro chamada SimpleFilter . Essa classe, em nosso caso, define a implementação personalizada do FilteredRowSet . Em seguida, aplicamos esse filtro no resultado retornado da consulta ao banco de dados. Filtragem significa limitar o número de linhas que serão visíveis. Portanto, aqui limitaremos o número de registros de informações do livro de acordo com o nome do autor selecionado fornecido.
Para a prática, a seguir estão as tabelas de banco de dados usadas com o próximo código Java.
Figura 1: Tabela de banco de dados, livro
Figura 2: Tabela de banco de dados, autor
Figura 3: Tabela de banco de dados, book_author
O SimpleFilter classe implementa o Predicado s avaliam métodos para implementar nosso filtro personalizado.
package org.mano.example; import javax.sql.RowSet; import javax.sql.rowset.Predicate; import java.sql.SQLException; public class SimpleFilter implements Predicate { private String[] authors; private String colname = null; private int colno = -1; public SimpleFilter(String[] authors, String colname) { this.authors = authors; this.colno = -1; this.colname = colname; } public SimpleFilter(String[] authors, int colno) { this.authors = authors; this.colno = colno; this.colname = null; } @Override public Boolean evaluate(Object value, String colName) { if (colName.equalsIgnoreCase(this.colname)) { for (String author : this.authors) { if (author.equalsIgnoreCase((String)value)) { return true; } } } return false; } @Override public Boolean evaluate(Object value, int colNumber) { if (colNumber == this.colno) { for (String author : this.authors) if (author.equalsIgnoreCase((String)value)) { return true; } } } return false } @Override public Boolean evaluate(RowSet rs) { if (rs == null) return false; try { for (int i=0;i<authors.length;i++) { String al = null; if (this.colno> 0) { al = (String)rs.getObject(this.colno); } else if (this.colname != null) { al = (String)rs.getObject(this.colname); } else { return false; } if (al.equalsIgnoreCase(authors[i])) { return true; } } } catch (SQLException e) { return false; } return false; } }
Esta classe é usada para executar o SimpleRowSet classe de filtro. Observe como usamos FilteredRowSet para filtrar dados no aplicativo. O processamento ocorre no nível do aplicativo e não no nível do banco de dados SQL. Como resultado, podemos implementar uma série de filtros e aplicá-los no mesmo conjunto de resultados para obter o resultado desejado. Isso aproveita o desempenho porque não precisamos disparar várias consultas ao banco de dados para obter um resultado modificado. Em vez disso, podemos aplicar vários filtros no resultado da consulta disparada uma vez no banco de dados. A aplicação tem duas fases importantes:
- Criamos um filtro que estabelece os critérios para filtrar os dados. Isso é feito implementando o Predicado interface. Pode haver vários construtores aceitando diferentes conjuntos de argumentos. Além disso, o filtro pode conter uma matriz de evaluate() métodos também aceitam diferentes conjuntos de argumentos com seu próprio conjunto distinto de implementação.
- O FilteredRowSet classe deve ser instanciada para obter o efeito desejado, algo que fizemos aqui com o applyFilter() método. O FilteredRowSet usa a classe de filtro personalizada que fornecemos para determinar os registros a serem visualizados.
package org.mano.example; import com.sun.rowset.FilteredRowSetImpl; import javax.sql.RowSet; import javax.sql.rowset.FilteredRowSet; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DemoApp { private static final String DB_URL = "jdbc:mysql://localhost:3306/my_lib"; private static final String DB_DRIVER = "com.mysql.cj.jdbc.Driver"; private static final String DB_USERNAME = "root"; private static final String DB_PASSWORD = "secret"; public static Connection conn = null; public static FilteredRowSet filteredRowSet = null; public static void main(String[] args) { try { Class.forName(DB_DRIVER); conn = DriverManager.getConnection(DB_URL, DB_USERNAME,DB_PASSWORD); System.out.println("Database connection successful."); applyFilter(); } catch (SQLException | ClassNotFoundException ex) { System.out.println(ex); } finally { if (conn != null) { try { conn.close(); catch (SQLException ex) { ex.printStackTrace(); } } if (filteredRowSet != null) { try { filteredRowSet.close(); } catch (SQLException ex) { ex.printStackTrace(); } } } } public static void applyFilter() { String[] arr = {"Donne", "Milton"}; SimpleFilter aFilter = new SimpleFilter(arr, 3); try { filteredRowSet = new FilteredRowSetImpl(); filteredRowSet.setCommand("SELECT title, f_name, l_name " + "FROM book_author BA, " + "author A, " + "book B " + "WHERE A.auth_id = BA.fk_author " + "AND B.book_id = BA.fk_book"); filteredRowSet.execute(conn); System.out.println ("--------------------------------------------"); System.out.println("Before applying any filter:"); System.out.println ("--------------------------------------------"); show(filteredRowSet); System.out.println ("--------------------------------------------"); System.out.println("After applying filter :"); System.out.println ("--------------------------------------------"); filteredRowSet.beforeFirst(); filteredRowSet.setFilter(aFilter); show(filteredRowSet); } catch (SQLException e) { e.printStackTrace(); } } public static void show(RowSet rs) { try { while (rs.next()) { System.out.println(rs.getString(1) + " / " + rs.getString(2) + " "+rs.getString(3)); } } catch (SQLException ex) { ex.printStackTrace(); } } }
Saída
Database connection successful. -------------------------------------------- Before applying any filter: -------------------------------------------- Gulliver's Travels / Jonathan Swift ... Ill Pensoroso / John Milton Areopagitica / John Milton -------------------------------------------- After applying filter: -------------------------------------------- The Flea / John Donne Holy Sonnet / John Donne Paradise Lost / John Milton Paradise Regained / John Milton Ill Pensoroso / John Milton Areopagitica / John Milton
Conclusão
Trabalhar com um grande número de linhas retornadas de uma consulta tem muitos problemas. Por um lado, os dados recuperados ocupam a memória.
Sempre ajuda a limitá-los de acordo com a necessidade e relevância. Com RowSet , podemos filtrá-los de acordo com um critério sem fazer nenhuma solicitação adicional ao banco de dados. Isso torna mais gerenciável trabalhar com linhas de banco de dados e alavanca a eficiência do código.