Ibland returnerar programförfrågningar till en databas ett stort antal rader. Även om hämtade data cachelagras i Resultatuppsättningen objekt är det ofta för stort för att arbeta med dem. Som ett resultat måste vi kunna filtrera dem i olika uppsättningar av data för att begränsa de synliga raderna. Den här artikeln fördjupar sig i att beskriva filtreringsaspekten av JDBC RowSet med lämpliga exempel.
En översikt över RowSet
RowSet är ett gränssnitt som kompletterar komponentmodellen JDBC API för JavaBeans. Den tillhandahåller en uppsättning egenskaper som gör att dess instans kan konfigureras för att ansluta till en JDBC-datakälla. Ett RowSet instans används främst för att hämta data från datakällan. Settermetoderna för detta gränssnitt används för att fylla i parametrarna för kommandoegenskapen för en SQL-fråga, som sedan används för att hämta poster från relationsdatabasen. Eftersom RowSet följer JavaBean-komponentmodellen, den stöder JavaBean-händelser. Dessa händelser används för att meddela andra komponenter om händelser, till exempel en värdeförändring på en raduppsättning. Eftersom RowSet gränssnittet är utformat som ett lager ovanför JDBC-drivrutinen, det är öppet för anpassad implementering. Denna frihet ger leverantören möjlighet att tillverka sin egen finjusterade effektuering och skicka den med JDBC-produkten.
Filtered RowSet
FilteredRowSet är en gränssnittstillägg av RowSet familj. Det finns en referensimplementering av detta gränssnitt, kallad FilteredRowSetImpl klass. För att tillhandahålla en anpassad implementering av FilteredRowSet gränssnittet kan man antingen utöka FilteredRowSetImpl klass eller använd FilteredRowSet gränssnitt enligt dina krav. Vid vissa tillfällen behöver vi tillämpa någon form av filtrering på innehållet som RowSet hämtar. En enkel möjlig lösning är att tillhandahålla ett frågespråk för alla RowSet implementeringar. Men då är detta inte ett hållbart tillvägagångssätt eftersom RowSet är byggd med idén om en frånkopplad lättviktskomponent. Detta skulle göra föremålet tungt och gå emot dess designprincip. Vi behöver ett tillvägagångssätt som tillgodoser behovet men som inte injicerar tungt frågespråk tillsammans med filtreringslogiken. JDBC FilteredRowSet standardimplementeringen utökar RowSet genom undergränssnitt som CachedRowSet och WebRowSet respektive. FilteredRowSet kan manipulera markören genom uppsättningen skyddade markörmanipulationsmetoder som tillhandahålls av CachedRowSet gränssnitt. Dessa metoder kan åsidosättas enligt krav och hjälp medan RowSet filtreras innehåll.
Ett snabbt exempel
Här är ett exempel för att illustrera hur FilteredRowSet används för att lagra innehållet som returneras av frågan som skickas till databasen. Resultatet av frågan filtreras enligt konfigurationen som tillämpas på FilteredRowset genomförande. Detta definierar det synliga innehållet eller raderna som vi är intresserade av från resultatet som returneras av frågan. I följande exempel har vi skapat en filterklass som heter SimpleFilter . Den här klassen definierar i vårt fall den anpassade implementeringen av FilteredRowSet . Vi tillämpade sedan detta filter på resultatet som returnerades från databasfrågan. Filtrering innebär att begränsa antalet rader som kommer att vara synliga. Därför kommer vi här att begränsa antalet bokinformationsposter enligt det valda författarnamnet.
För hands on, följande är databastabellerna som används med den kommande Java-koden.
Figur 1: Databastabell, bok
Figur 2: Databastabell, författare
Figur 3: Databastabell, bokförfattare
SimpleFilter klass implementerar Predikatet utvärderar metoder för att implementera vårt anpassade filter.
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; } }
Denna klass används för att köra SimpleRowSet filterklass. Notera hur vi har använt FilteredRowSet för att filtrera data i applikationen. Bearbetningen sker på applikationsnivå snarare än på SQL-databasnivå. Som ett resultat kan vi implementera en serie filter och tillämpa dem på samma resultatuppsättning för att få önskat resultat. Detta utnyttjar prestandan eftersom vi inte behöver skicka flera frågor till databasen för att få ett modifierat resultat. Istället kan vi tillämpa flera filtrering på frågeresultatet som avfyrades en gång i databasen. Applikationen har två viktiga faser:
- Vi skapar ett filter som anger kriterierna för att filtrera data. Detta görs genom att implementera Predikatet gränssnitt. Det kan finnas flera konstruktörer som accepterar olika uppsättningar argument. Filtret kan också innehålla en array av evaluate() metoder som också accepterar olika uppsättningar argument med sin egen distinkta uppsättning implementering.
- Filtered RowSet klass måste instansieras för att få önskad effekt, något som vi har gjort här med applyFilter() metod. FilteredRowSet använder den anpassade filterklassen vi har tillhandahållit för att avgöra vilka poster som ska visas.
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(); } } }
Utdata
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
Slutsats
Att arbeta med ett stort antal rader som returneras från en fråga har många problem. För det första upptar data som hämtas minnet.
Det hjälper alltid att begränsa dem efter behov och relevans. Med RowSet , kan vi filtrera dem enligt ett kriterium utan att göra några ytterligare databasförfrågningar. Detta gör det mer hanterbart att arbeta med databasrader och utnyttjar effektiviteten i koden.