Czasami zapytania aplikacji do bazy danych zwracają dużą liczbę wierszy. Chociaż pobrane dane są buforowane w ResultSet obiekt, często jest zbyt duży, aby z nimi pracować. W rezultacie musimy być w stanie filtrować je w różnych zestawach danych, aby ograniczyć widoczne wiersze. Ten artykuł zagłębia się w opis aspektu filtrowania JDBC RowSet z odpowiednimi przykładami.
Przegląd RowSet
Zestaw wierszy jest interfejsem uzupełniającym model komponentów JDBC API for JavaBeans. Udostępnia zestaw właściwości, który umożliwia skonfigurowanie jego instancji do łączenia się ze źródłem danych JDBC. Zestaw wierszy instancja służy przede wszystkim do pobierania danych ze źródła danych. Metody ustawiające tego interfejsu są używane do wypełniania parametrów właściwości polecenia zapytania SQL, które następnie są używane do pobierania rekordów z relacyjnej bazy danych. Ponieważ RowSet jest zgodny z modelem komponentów JavaBean, obsługuje zdarzenia JavaBean. Te zdarzenia są używane do powiadamiania innych składników o zdarzeniach, takich jak zmiana wartości w zestawie wierszy. Ponieważ RowSet Interfejs jest zaprojektowany jako warstwa nad sterownikiem JDBC, jest otwarty na niestandardowe implementacje. Ta swoboda umożliwia sprzedawcy tworzenie własnych, dopracowanych efektów i dostarczanie ich z produktem JDBC.
Filtrowany zestaw wierszy
Filtrowany zestaw wierszy jest rozszerzeniem interfejsu RowSet rodzina. Istnieje referencyjna implementacja tego interfejsu o nazwie FiltedRowSetImpl klasa. Aby zapewnić niestandardową implementację FiltedRowSet interfejs, można rozszerzyć FiltedRowSetImpl lub użyj FilteredRowSet interfejs zgodnie z wymaganiami. W niektórych przypadkach musimy zastosować jakąś formę filtrowania treści, które RowSet pobiera. Prostym możliwym rozwiązaniem jest zapewnienie języka zapytań dla wszystkich RowSet wdrożenia. Ale z drugiej strony nie jest to opłacalne podejście, ponieważ RowSet jest zbudowany z myślą o odłączonym, lekkim komponencie. To spowodowałoby, że obiekt byłby ciężki i byłby sprzeczny z jego zasadą projektowania. Potrzebujemy podejścia, które odpowiada na tę potrzebę, ale nie wstrzykuje ciężkiego języka zapytań wraz z logiką przetwarzania filtrowania. JDBC FilteredRowSet standardowa implementacja rozszerza RowSet przez podinterfejsy, takie jak CachedRowSet i WebRowSet odpowiednio. Filtrowany zestaw wierszy może manipulować kursorem za pomocą zestawu chronionych metod manipulowania kursorem dostarczonych przez CachedRowSet berło. Te metody można zastąpić zgodnie z wymaganiami i pomocą podczas filtrowania RowSet treść.
Szybki przykład
Oto przykład ilustrujący, jak FiltedRowSet służy do przechowywania zawartości zwróconej przez zapytanie do bazy danych. Wynik zapytania jest filtrowany zgodnie z konfiguracją zastosowaną do FiltedRowset realizacja. Definiuje widoczną treść lub interesujące nas wiersze z wyniku zwróconego przez zapytanie. W poniższym przykładzie stworzyliśmy klasę filtra o nazwie SimpleFilter . Ta klasa w naszym przypadku definiuje niestandardową implementację FiltedRowSet . Następnie zastosowaliśmy ten filtr do wyniku zwróconego z zapytania do bazy danych. Filtrowanie oznacza ograniczenie liczby wierszy, które będą widoczne. Dlatego tutaj ograniczymy liczbę rekordów informacji o książkach zgodnie z podaną wybraną nazwą autora.
Aby uzyskać więcej informacji, poniżej znajdują się tabele bazy danych używane w nadchodzącym kodzie Java.
Rysunek 1: Tabela bazy danych, książka
Rysunek 2: Tabela bazy danych, autor
Rysunek 3: Tabela bazy danych, book_author
Prosty filtr klasa implementuje Predykat metody oceny w celu wdrożenia naszego niestandardowego filtra.
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; } }
Ta klasa jest używana do wykonania SimpleRowSet klasa filtra. Zwróć uwagę, jak wykorzystaliśmy FiltedRowSet do filtrowania danych w aplikacji. Przetwarzanie odbywa się na poziomie aplikacji, a nie na poziomie bazy danych SQL. W rezultacie możemy zaimplementować szereg filtrów i zastosować je na tym samym zestawie wyników, aby uzyskać pożądany wynik. Zwiększa to wydajność, ponieważ nie musimy uruchamiać wielu zapytań do bazy danych, aby uzyskać zmodyfikowany wynik. Zamiast tego możemy zastosować wielokrotne filtrowanie na wyniku zapytania, który został odpalony raz do bazy danych. Aplikacja składa się z dwóch ważnych etapów:
- Tworzymy filtr, który określa kryteria filtrowania danych. Odbywa się to poprzez zaimplementowanie Predykatu berło. Może istnieć wiele konstruktorów akceptujących różne zestawy argumentów. Ponadto filtr może zawierać tablicę evaluate() metody akceptujące również różne zestawy argumentów z własnym, odrębnym zestawem implementacji.
- Filtrowany zestaw wierszy klasa musi być skonkretyzowana, aby uzyskać pożądany efekt, coś, co zrobiliśmy tutaj za pomocą applyFilter() metoda. Filtrowany zestaw wierszy używa niestandardowej klasy filtra, którą dostarczyliśmy, aby określić rekordy do wyświetlenia.
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(); } } }
Wyjście
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
Wniosek
Praca z dużą liczbą wierszy zwracanych z zapytania wiąże się z wieloma problemami. Po pierwsze, odzyskane dane zajmują pamięć.
Zawsze pomaga je ograniczyć zgodnie z potrzebą i trafnością. Z RowSet , możemy je filtrować według kryterium bez dodatkowych zapytań do bazy danych. Ułatwia to pracę z wierszami bazy danych i zwiększa wydajność kodu.