A veces, las consultas de la aplicación a una base de datos devuelven una gran cantidad de filas. Aunque los datos obtenidos se almacenan en caché dentro del ResultSet objeto, a menudo es demasiado grande para trabajar con ellos. Como resultado, debemos poder filtrarlos en diferentes conjuntos de datos para limitar las filas visibles. Este artículo profundiza en la descripción del aspecto de filtrado de JDBC RowSet con ejemplos apropiados.
Una descripción general de RowSet
Conjunto de filas es una interfaz que complementa el modelo de componentes de la API de JDBC para JavaBeans. Proporciona un conjunto de propiedades que permite configurar su instancia para conectarse a una fuente de datos JDBC. Un Conjunto de filas La instancia se utiliza principalmente para recuperar datos del origen de datos. Los métodos setter de esta interfaz se usan para completar los parámetros de la propiedad de comando de una consulta SQL, que luego se usa para obtener registros de la base de datos relacional. Porque RowSet se adhiere al modelo de componentes JavaBean, admite eventos JavaBean. Estos eventos se usan para notificar a otros componentes sobre eventos, como un cambio de valor en un conjunto de filas. Porque el RowSet La interfaz está diseñada como una capa sobre el controlador JDBC, está abierta a una implementación personalizada. Esta libertad faculta al proveedor para fabricar su propia ejecución afinada y enviarla con el producto JDBC.
El conjunto de filas filtradas
El conjunto de filas filtradas es una extensión de interfaz de RowSet familia. Hay una implementación de referencia de esta interfaz, llamada FilteredRowSetImpl clase. Para proporcionar una implementación personalizada de FilteredRowSet interfaz, uno puede extender el FilteredRowSetImpl class o use el FilteredRowSet interfaz según su requisito. En algunas ocasiones, necesitamos aplicar algún tipo de filtrado en el contenido que RowSet recupera Una posible solución simple es proporcionar un lenguaje de consulta para todos los RowSet implementaciones. Pero entonces, este no es un enfoque viable porque RowSet está construido con la idea de un componente ligero desconectado. Esto haría que el objeto fuera pesado e iría en contra de su principio de diseño. Necesitamos un enfoque que aborde la necesidad pero que no inyecte un lenguaje de consulta pesado junto con la lógica de procesamiento del filtrado. El FilteredRowSet de JDBC la implementación estándar extiende RowSet a través de subinterfaces como CachedRowSet y WebRowSet respectivamente. El conjunto de filas filtradas puede manipular el cursor a través del conjunto de métodos de manipulación de cursores protegidos proporcionados por el CachedRowSet interfaz. Estos métodos se pueden anular según los requisitos y ayudar al filtrar RowSet contenido.
Un ejemplo rápido
Aquí hay un ejemplo para ilustrar cómo FilteredRowSet se utiliza para almacenar los contenidos devueltos por la consulta disparada a la base de datos. El resultado de la consulta se filtra según la configuración aplicada al FilteredRowset implementación. Esto define el contenido visible o las filas que nos interesan del resultado devuelto por la consulta. En el siguiente ejemplo, hemos creado una clase de filtro llamada SimpleFilter . Esta clase, en nuestro caso, define la implementación personalizada del FilteredRowSet . Luego aplicamos este filtro en el resultado devuelto por la consulta de la base de datos. Filtrado significa limitar el número de filas que serán visibles. Por lo tanto, aquí limitaremos la cantidad de registros de información del libro según el nombre del autor seleccionado proporcionado.
A modo práctico, las siguientes son las tablas de la base de datos utilizadas con el próximo código Java.
Figura 1: Tabla de base de datos, libro
Figura 2: Tabla de base de datos, autor
Figura 3: Tabla de base de datos, book_author
El SimpleFilter clase implementa el Predicado Los métodos de evaluación para implementar nuestro 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 clase se usa para ejecutar SimpleRowSet clase de filtro. Observe cómo hemos utilizado FilteredRowSet para filtrar datos en la aplicación. El procesamiento se produce en el nivel de la aplicación en lugar de en el nivel de la base de datos SQL. Como resultado, podemos implementar una serie de filtros y aplicarlos sobre el mismo conjunto de resultados para obtener el resultado deseado. Esto aprovecha el rendimiento porque no tenemos que realizar múltiples consultas a la base de datos para obtener un resultado modificado. En su lugar, podemos aplicar filtros múltiples en el resultado de la consulta disparado una vez a la base de datos. La aplicación tiene dos fases importantes:
- Creamos un filtro que establece los criterios para filtrar los datos. Esto se hace implementando el Predicado interfaz. Puede haber múltiples constructores que acepten diferentes conjuntos de argumentos. Además, el filtro puede contener una matriz de evaluate() métodos que también aceptan diferentes conjuntos de argumentos con su propio conjunto distinto de implementación.
- El conjunto de filas filtradas la clase debe ser instanciada para obtener el efecto deseado, algo que hemos hecho aquí con applyFilter() método. El conjunto de filas filtradas utiliza la clase de filtro personalizado que hemos proporcionado para determinar los registros que se verán.
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(); } } }
Salida
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
Conclusión
Trabajar con una gran cantidad de filas devueltas por una consulta tiene muchos problemas. Por un lado, los datos recuperados ocupan memoria.
Siempre es útil limitarlos según la necesidad y la relevancia. Con Conjunto de filas , podemos filtrarlos según un criterio sin realizar ninguna solicitud adicional a la base de datos. Esto hace que sea más manejable trabajar con las filas de la base de datos y aprovecha la eficiencia del código.