Veiledning til JDBC ResultSet-grensesnitt

1. Oversikt

Java Database Connectivity (JDBC) API gir tilgang til databasen fra et Java-program. Vi kan bruke JDBC til å koble til hvilken som helst database så lenge den støttede JDBC-driveren er tilgjengelig.

De ResultatSett er en tabell over data generert ved å utføre databasespørsmål. I denne opplæringen skal vi se nærmere på ResultatSett API.

2. Generere en ResultatSett

Først henter vi a ResultatSett ved å ringe executeQuery () på ethvert objekt som implementerer Uttalelse grensesnitt. Begge PreparedStatement og CallableStatement er undergrensesnitt for Uttalelse:

PreparedStatement pstmt = dbConnection.prepareStatement ("velg * fra ansatte"); ResultSet rs = pstmt.executeQuery ();

De ResultatSett objektet opprettholder en markør som peker til gjeldende rad i resultatsettet. Vi bruker neste () på vår ResultatSett å gjenta gjennom postene.

Neste skal vi bruke getX () metoder mens det gjentas gjennom resultatene for å hente verdiene fra databasekolonnene, hvor X er datatypen for kolonnen. Faktisk vil vi gi databasekolonnavn til getX () metoder:

while (rs.next ()) {String name = rs.getString ("name"); Heltall empId = rs.getInt ("emp_id"); Dobbel lønn = rs.getDouble ("lønn"); Strengposisjon = rs.getString ("posisjon"); } 

Like måte, indeksnummeret til kolonnen kan brukes med getX () metoder i stedet for kolonnenavnet. Indeksnummeret er sekvensen til kolonnene i SQL select-setningen.

Hvis den valgte setningen ikke viser kolonnenavn, er indeksnummeret kolonnesekvensen i tabellen. Kolonneindeksnummereringen starter fra en:

Heltall empId = rs.getInt (1); Strengnavn = rs.getString (2); Strengposisjon = rs.getString (3); Dobbel lønn = rs.getDouble (4); 

3. Henter MetaData fra ResultatSett

I denne delen ser vi hvordan du kan hente informasjon om kolonneegenskapene og typene i a ResultatSett.

La oss først bruke getMetaData () metode på vår ResultatSett for å få tak i ResultatSetMetaData:

ResultSetMetaData metaData = rs.getMetaData ();

Deretter, la oss få antall kolonner som er i vår ResultatSett:

Heltall columnCount = metaData.getColumnCount ();

Videre kan vi bruke noen av metodene nedenfor på metadataobjektet for å hente egenskaper for hver kolonne:

  • getColumnName (int columnNumber) for å få navnet på kolonnen
  • getColumnLabel (int columnNumber) for å få tilgang til etiketten til kolonnen, som er spesifisert etter SOM i SQL-spørringen
  • getTableName (int columnNumber) for å få tabellnavnet denne kolonnen tilhører
  • getColumnClassName (int columnNumber) for å skaffe Java-datatypen til kolonnen
  • getColumnTypeName (int columnNumber) for å få datatypen til kolonnen i databasen
  • getColumnType (int columnNumber) for å få SQL-datatypen til kolonnen
  • isAutoIncrement (int columnNumber) indikerer om kolonnen er automatisk økning
  • isCaseSensitive (int columnNumber) spesifiserer om kolonnesaken har betydning
  • er søkbar (int columnNumber) foreslår om vi kan bruke kolonnen i hvor klausul i SQL-spørringen
  • isCurrency (int columnNumber) signaliserer om kolonnen inneholder en kontantverdi
  • isNullable (int columnNumber) returnerer null hvis kolonnen ikke kan være null, en hvis kolonnen kan inneholde en nullverdi, og to hvis kolonnens ugyldighet er ukjent
  • isSigned (int columnNumber) returnerer ekte hvis verdier i kolonnen er signert, returneres ellers falsk

La oss gjenta gjennom kolonnene for å få deres egenskaper:

for (int columnNumber = 1; columnNumber <= columnCount; columnNumber ++) {String catalogName = metaData.getCatalogName (columnNumber); String className = metaData.getColumnClassName (columnNumber); Strengetikett = metaData.getColumnLabel (columnNumber); Strengnavn = metaData.getColumnName (columnNumber); Streng typeName = metaData.getColumnTypeName (columnNumber); int type = metaData.getColumnType (columnNumber); String tableName = metaData.getTableName (columnNumber); String schemaName = metaData.getSchemaName (columnNumber); boolsk isAutoIncrement = metaData.isAutoIncrement (columnNumber); boolsk isCaseSensitive = metaData.isCaseSensitive (columnNumber); boolsk isCurrency = metaData.isCurrency (columnNumber); boolsk isDefiniteWritable = metaData.isDefinitelyWritable (columnNumber); boolsk isReadOnly = metaData.isReadOnly (columnNumber); boolsk isSearchable = metaData.isSearchable (columnNumber); boolsk isReadable = metaData.isReadOnly (columnNumber); boolsk isSigned = metaData.isSigned (columnNumber); boolsk isWritable = metaData.isWritable (columnNumber); int nullable = metaData.isNullable (columnNumber); }

4. Navigere i ResultatSett

Når vi får en ResultatSett, markørens plassering er før første rad. Videre er som standard ResultatSett beveger seg bare fremover. Men vi kan bruke en rullbar ResultatSett for andre navigasjonsalternativer.

I denne delen vil vi diskutere de forskjellige navigasjonsalternativene.

4.1. ResultatSett Typer

ResultatSett type indikerer hvordan vi styrer gjennom datasettet:

  • TYPE_FORWARD_ONLY - standardalternativet der markøren beveger seg fra start til slutt
  • TYPE_SCROLL_INSENSITIVE - markøren vår kan bevege seg gjennom datasettet i både fremover og bakover retning; hvis det er endringer i de underliggende dataene mens du går gjennom datasettet, ignoreres de; datasettet inneholder dataene fra det tidspunktet databasespørringen returnerer resultatet
  • TYPE_SCROLL_SENSITIVE - i likhet med typen som ikke er følsom, men for denne typen reflekterer datasettet umiddelbart eventuelle endringer i de underliggende dataene

Ikke alle databaser støtter alle ResultatSett typer. Så la oss sjekke om typen støttes ved hjelp av supportsResultSetType på vår DatabaseMetaData gjenstand:

DatabaseMetaData dbmd = dbConnection.getMetaData (); boolsk isSupported = dbmd.supportsResultSetType (ResultSet.TYPE_SCROLL_INSENSITIVE);

4.2. Scrollable ResultSet

For å få en rullbar ResultatSett, vi må passere noen ekstra parametere mens du forbereder Uttalelse.

For eksempel ville vi få en rullbar ResultatSett ved å bruke en av dem TYPE_SCROLL_INSENSITIVE eller TYPE_SCROLL_SENSITIVE som en ResultatSett type:

PreparedStatement pstmt = dbConnection.prepareStatement ("velg * fra ansatte", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery (); 

4.3. Navigasjonsalternativer

Vi kan bruke et av alternativene nedenfor på en rullbar ResultatSett:

  • neste () - fortsetter til neste rad fra gjeldende posisjon
  • tidligere() - går til forrige rad
  • først () - navigerer til første rad i ResultatSett
  • siste() - hopper til siste rad
  • beforeFirst () - går til start; ringer neste () på vår ResultatSett etter å ha kalt denne metoden returnerer den første raden fra vår ResultatSett
  • afterLast () - sprang til slutten; ringer forrige () på ResultSet etter å ha utført denne metoden returnerer den siste raden fra vår ResultatSett
  • relativ (int numOfRows) - gå fremover eller bakover fra gjeldende posisjon av numOfRows
  • absolutt (int rowNumber) - hopper til radnummer spesifisert

La oss se noen eksempler:

PreparedStatement pstmt = dbConnection.prepareStatement ("velg * fra ansatte", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery (); mens (rs.next ()) {// itererer gjennom resultatene fra første til siste} rs.beforeFirst (); // hopper tilbake til startpunktet, før første rad rs.afterLast (); // hopper til slutten av resultatsettet rs.first (); // navigerer til første rad rs.last (); // går til siste rad rs.absolute (2); // hopper til 2. rad rs.relativ (-1); // hopper til forrige rad rs.relativ (2); // hopper fremover to rader mens (rs.previous ()) {// itererer fra gjeldende rad til første rad i bakoverretning} 

4.4. ResultatSett Radtelling

La oss bruke getRow () for å få gjeldende radnummer på vårt ResultatSett.

Først navigerer vi til den siste raden i ResultatSett og bruk deretter getRow () for å få antall poster:

rs.last (); int rowCount = rs.getRow ();

5. Oppdatere data i a ResultatSett

Som standard er ResultatSett er skrivebeskyttet. Vi kan imidlertid bruke en oppdaterbar ResultatSett for å sette inn, oppdatere og slette radene.

5.1. ResultatSett Samtidighet

Samtidig modus indikerer om vår ResultatSett kan oppdatere dataene.

De CONCUR_READ_ONLY alternativet er standard og bør brukes hvis vi ikke trenger å oppdatere dataene ved hjelp av vår ResultatSett.

Imidlertid hvis vi trenger å oppdatere dataene i vår ResultatSett, og så CONCUR_UPDATABLE alternativet skal brukes.

Ikke alle databaser støtter alle samtidighetsmodusene for alle ResultatSett typer. Derfor må vi sjekke om ønsket type og samtidighetsmodus støttes ved hjelp av supportsResultSetConcurrency () metode:

DatabaseMetaData dbmd = dbConnection.getMetaData (); boolsk isSupported = dbmd.supportsResultSetConcurrency (ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); 

5.2. Få en oppdaterbar ResultatSett

For å få en oppdaterbar ResultatSett, må vi passere en ekstra parameter når vi forbereder Uttalelse. La oss bruke det CONCUR_UPDATABLE som den tredje parameteren mens du oppretter en uttalelse:

PreparedStatement pstmt = dbConnection.prepareStatement ("velg * fra ansatte", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery ();

5.3. Oppdaterer en rad

I denne delen oppdaterer vi en rad ved hjelp av den oppdaterbare ResultatSett opprettet i forrige seksjon.

Vi kan oppdatere data på rad ved å ringe updateX () metoder, sender kolonnenavn og verdier som skal oppdateres. Vi kan bruke hvilken som helst støttet datatype i stedet for X i updateX () metode.

La oss oppdatere "lønn" kolonne, som er av typen dobbelt:

rs.updateDouble ("lønn", 1100.0);

Merk at dette bare oppdaterer dataene i ResultatSett, men endringene er ennå ikke lagret i databasen.

Til slutt, la oss ringe updateRow () til lagre oppdateringene i databasen:

rs.updateRow (); 

I stedet for kolonnenavnene kan vi sende kolonneindeksen til updateX () metoder. Dette ligner på å bruke kolonneindeksen for å få verdiene med getX () metoder. Passer enten kolonnenavnet eller indeksen til updateX () metoder gir samme resultat:

rs.updateDouble (4, 1100.0); rs.updateRow (); 

5.4. Sette inn en rad

La oss nå sette inn en ny rad ved hjelp av vår oppdaterbare ResultatSett.

Først skal vi bruke moveToInsertRow () for å flytte markøren for å sette inn en ny rad:

rs.moveToInsertRow ();

Deretter må vi ringe updateX () metoder for å legge til informasjonen i raden. Vi må gi data til alle kolonnene i databasetabellen. Hvis vi ikke gir data til hver kolonne, brukes standard kolonneverdi:

rs.updateString ("navn", "Venkat"); rs.updateString ("posisjon", "DBA"); rs.updateDouble ("lønn", 925.0);

La oss så ringe insertRow () for å sette inn en ny rad i databasen:

rs.insertRow ();

Til slutt, la oss bruke moveToCurrentRow (). Dette vil ta markørposisjonen tilbake til raden vi var på før vi begynte å sette inn en ny rad ved hjelp av moveToInsertRow () metode:

rs.moveToCurrentRow ();

5.5. Slette en rad

I denne delen vil vi slette en rad ved hjelp av vår oppdaterbare ResultatSett.

Først navigerer vi til raden vi vil slette. Så vil vi ringe deleteRow () metode for å slette gjeldende rad:

rs.absolutt (2); rs.deleteRow ();

6. Holdbarhet

Holdbarheten avgjør om vår ResultatSett vil være åpen eller stengt ved slutten av en databasetransaksjon.

6.1. Holdbarhetstyper

Bruk CLOSE_CURSORS_AT_COMMIT hvis ResultatSett kreves ikke etter at transaksjonen er begått.

Bruk HOLD_CURSORS_OVER_COMMIT for å lage en holdbar ResultatSett. En holdbar ResultatSett er ikke stengt selv etter at databasetransaksjonen er begått.

Ikke alle databaser støtter alle holdbarhetstyper.

Så la oss sjekk om holdbarhetstypen støttes ved hjelp av supportsResultSetHoldability () på vår DatabaseMetaData gjenstand. Deretter får vi standardholdbarheten til databasen ved hjelp av getResultSetHoldability ():

boolsk isCloseCursorSupported = dbmd.supportsResultSetHoldability (ResultSet.CLOSE_CURSORS_AT_COMMIT); boolsk isOpenCursorSupported = dbmd.supportsResultSetHoldability (ResultSet.HOLD_CURSORS_OVER_COMMIT); boolsk standardHoldability = dbmd.getResultSetHoldability ();

6.2. Holdbar ResultatSett

Å lage en holdbar ResultatSett, må vi spesifisere holdbarhet skriv inn som siste parameter mens du oppretter en Uttalelse. Denne parameteren er spesifisert etter samtidighetsmodus.

Merk at hvis vi bruker Microsoft SQL Server (MSSQL), må vi angi holdbarhet på databasetilkoblingen, i stedet for på ResultatSett:

dbConnection.setHoldability (ResultSet.HOLD_CURSORS_OVER_COMMIT);

La oss se dette i aksjon. La oss først lage en Uttalelse, setter holdbarheten til HOLD_CURSORS_OVER_COMMIT:

Uttalelse pstmt = dbConnection.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.HOLD_CURSORS_OVER_COMMIT)

La oss nå oppdatere en rad mens vi henter dataene. Dette ligner på oppdateringseksemplet vi diskuterte tidligere, bortsett fra at vi fortsetter å iterere gjennom ResultatSett etter å ha begått oppdateringstransaksjonen til databasen. Dette fungerer bra på både MySQL- og MSSQL-databaser:

dbConnection.setAutoCommit (false); ResultSet rs = pstmt.executeQuery ("velg * fra ansatte"); while (rs.next ()) {if (rs.getString ("name"). equalsIgnoreCase ("john")) {rs.updateString ("name", "John Doe"); rs.updateRow (); dbConnection.commit (); }} rs.last (); 

Det er verdt å merke seg at MySQL bare støtter HOLD_CURSORS_OVER_COMMIT. Så, selv om vi bruker CLOSE_CURSORS_AT_COMMIT, vil det bli ignorert.

MSSQL-databasen støtter CLOSE_CURSORS_AT_COMMIT. Dette betyr at ResultatSett vil bli stengt når vi begår transaksjonen. Som et resultat, et forsøk på å få tilgang til ResultatSett etter at transaksjonen har begått, resulterer det i en feil med markøren er ikke åpen. Derfor kan vi ikke hente ytterligere poster fra ResultatSett.

7. Hent størrelse

Vanligvis når du laster data i en ResultatSett, bestemmer databasedriverne antall rader som skal hentes fra databasen. På en MySQL-database, for eksempel, ResultatSett laster normalt alle postene i minnet på en gang.

Noen ganger kan det imidlertid hende at vi trenger å håndtere et stort antall poster som ikke passer inn i vårt JVM-minne. I dette tilfellet kan vi bruke egenskapen fetch size enten på vår Uttalelse eller ResultatSett objekter for å begrense antall poster som opprinnelig ble returnert.

Når ytterligere resultater kreves, ResultatSett henter et nytt antall poster fra databasen. Ved å bruke egenskapen fetch size kan vi gi et forslag til databasedriveren om antall rader som skal hentes per databasetur. Hentingsstørrelsen vi spesifiserer vil bli brukt på de påfølgende databaseturene.

Hvis vi ikke spesifiserer hentestørrelsen for vår ResultatSett, deretter hentestørrelsen på Uttalelse benyttes. Hvis vi ikke spesifiserer hentestørrelse for verken Uttalelse eller ResultatSett, så brukes databasestandarden.

7.1. Bruker hentestørrelse på Uttalelse

La oss nå se hentestørrelsen på Uttalelse i aksjon. Vi angir hentestørrelsen på Uttalelse til 10 poster. Hvis spørringen vår returnerer 100 poster, vil det være 10 rundturer i databasen, og laster inn 10 poster hver gang:

PreparedStatement pstmt = dbConnection.prepareStatement ("velg * fra ansatte", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); pstmt.setFetchSize (10); ResultSet rs = pstmt.executeQuery (); mens (rs.next ()) {// itererer gjennom resultatsettet}

7.2. Bruker hentestørrelse på ResultatSett

La oss nå endre hentestørrelsen i vårt forrige eksempel ved hjelp av ResultatSett.

Først bruker vi hentestørrelsen på vår Uttalelse. Dette tillater vårt ResultatSett for å laste inn 10 poster først etter at spørringen er utført.

Deretter endrer vi hentestørrelsen på ResultatSett. Dette vil overstyre hentestørrelsen vi tidligere spesifiserte på vår Uttalelse. Så alle påfølgende turer vil laste 20 poster til alle postene er lastet.

Som et resultat vil det bare være 6 databaseturer for å laste alle postene:

PreparedStatement pstmt = dbConnection.prepareStatement ("velg * fra ansatte", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); pstmt.setFetchSize (10); ResultSet rs = pstmt.executeQuery (); rs.setFetchSize (20); mens (rs.next ()) {// itererer gjennom resultatsettet}

Til slutt vil vi se hvordan du endrer hentningsstørrelsen til ResultatSett mens det gjentas resultatene.

I likhet med forrige eksempel vil vi først sette hentestørrelsen til 10 på vår Uttalelse. Så, de første 3 databaseturene våre laster 10 poster per hver tur.

Og så endrer vi hentestørrelsen på vår ResultatSett til 20 mens du leser den 30. plata. Så de neste 4 turene vil laste 20 poster per hver tur.

Derfor trenger vi 7 databaseturer for å laste alle 100 poster:

PreparedStatement pstmt = dbConnection.prepareStatement ("velg * fra ansatte", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); pstmt.setFetchSize (10); ResultSet rs = pstmt.executeQuery (); int rowCount = 0; mens (rs.next ()) {// itererer gjennom resultatsettet hvis (rowCount == 30) {rs.setFetchSize (20); } rowCount ++; }

8. Konklusjon

I denne artikkelen så vi hvordan du bruker ResultatSett API for å hente og oppdatere data fra en database. Flere av de avanserte funksjonene vi diskuterte er avhengig av databasen vi bruker. Derfor må vi sjekke støtten for disse funksjonene før vi bruker dem.

Som alltid er koden tilgjengelig på GitHub.