Vodič kroz JDBC ResultSet sučelje

1. Pregled

API povezivanja baze podataka Java (JDBC) omogućuje pristup bazi podataka iz Java aplikacije. JDBC možemo koristiti za povezivanje s bilo kojom bazom podataka sve dok je dostupan podržani JDBC pokretački program.

The Postavi rezultat je tablica podataka generiranih izvršavanjem upita baze podataka. U ovom uputstvu ćemo dublje pogledati Postavi rezultat API.

2. Stvaranje a Postavi rezultat

Prvo dohvaćamo a Postavi rezultat pozivanjem executeQuery () na bilo kojem objektu koji provodi Izjava sučelje. Oboje PreparedStatement i CallableStatement su podsučelja Izjava:

PreparedStatement pstmt = dbConnection.prepareStatement ("odaberite * od zaposlenika"); RezultatSkup rs = pstmt.executeQuery ();

The Postavi rezultat objekt održava kursor koji pokazuje na trenutni redak skupa rezultata. Koristit ćemo Sljedeći() na naš Postavi rezultat prelistavati zapise.

Dalje, mi ćemo koristiti getX () metode tijekom iteriranja kroz rezultate za dohvaćanje vrijednosti iz stupaca baze podataka, gdje x je tip podataka stupca. U stvari, dat ćemo imena stupaca baze podataka na getX () metode:

while (rs.next ()) {String name = rs.getString ("name"); Cijeli broj empId = rs.getInt ("emp_id"); Dvostruka plaća = rs.getDouble ("plaća"); Položaj niza = rs.getString ("položaj"); } 

Također, indeksni broj stupca može se koristiti s getX () metode umjesto naziva stupca. Broj indeksa je slijed stupaca u SQL naredbi za odabir.

Ako u naredbi select nisu navedena imena stupaca, indeksni je broj slijed stupaca u tablici. Numeriranje indeksa stupaca počinje od jednog:

Cijeli broj empId = rs.getInt (1); Naziv niza = rs.getString (2); Položaj niza = rs.getString (3); Dvostruka plaća = rs.getDouble (4); 

3. Dohvaćanje metapodataka iz Postavi rezultat

U ovom ćemo odjeljku vidjeti kako doći do podataka o svojstvima i vrstama stupaca u a Postavi rezultat.

Prvo, upotrijebimo getMetaData () metoda na našem Postavi rezultat kako bi se dobio ResultSetMetaData:

ResultSetMetaData metaData = rs.getMetaData ();

Dalje, uzmimo broj stupaca koji se nalaze u našem Postavi rezultat:

Cjeloviti stupacCount = metaData.getColumnCount ();

Nadalje, možemo koristiti bilo koju od dolje navedenih metoda na našem objektu metapodataka za dohvaćanje svojstava svakog stupca:

  • getColumnName (int columnNumber) da bi se dobio naziv stupca
  • getColumnLabel (int columnNumber) za pristup oznaci stupca koja je navedena nakon KAO u SQL upitu
  • getTableName (int columnNumber) da biste dobili ime tablice kojoj pripada ovaj stupac
  • getColumnClassName (int columnNumber) za stjecanje Java tipa podataka stupca
  • getColumnTypeName (int columnNumber) da biste dobili tip podataka stupca u bazi podataka
  • getColumnType (int columnNumber) da biste dobili SQL vrstu podataka stupca
  • isAutoIncrement (int columnNumber) označava je li stupac automatski povećan
  • isCaseSensitive (int columnNumber) određuje je li slučaj stupca važan
  • isSearchable (int columnNumber) sugerira možemo li koristiti stupac u gdje klauzula SQL upita
  • isCurrency (int columnNumber) signalizira sadrži li stupac novčanu vrijednost
  • isNullable (int columnNumber) vraća se nula ako stupac ne može biti null, jedan ako stupac može sadržavati null vrijednost, i dva ako je nepoznatost stupca nepoznata
  • isSigned (int columnNumber) vraća se pravi ako su vrijednosti u stupcu potpisane, u suprotnom se vraća lažno

Prelistajmo stupce da bismo dobili njihova svojstva:

for (int columnNumber = 1; NumberBill <= columnCount; columnNumber ++) {StringName kataloga = metaData.getCatalogName (Broj stupaca); Niz klaseName = metaData.getColumnClassName (NumberNumber); Oznaka niza = metaData.getColumnLabel (broj stupca); Naziv niza = metaData.getColumnName (NumberNumber); Niz tipaName = metaData.getColumnTypeName (Brog stupca); int vrsta = metaData.getColumnType (broj stupca); Niz niza tablica = metaData.getTableName (broj stupca); Niz shemaName = metaData.getSchemaName (Broj stupaca); logička vrijednost jeAutoIncrement = metaData.isAutoIncrement (NumberNumber); boolean isCaseSensitive = metaData.isCaseSensitive (columnNumber); boolean isCurrency = metaData.isCurrency (NumberNumber); boolean isDefiniteWritable = metaData.isDefinitelyWritable (columnNumber); boolean isReadOnly = metaData.isReadOnly (columnNumber); boolean isSearchable = metaData.isSearchable (columnNumber); boolean isReadable = metaData.isReadOnly (columnNumber); boolean isSigned = metaData.isSigned (columnNumber); boolean isWritable = metaData.isWritable (columnNumber); int nullable = metaData.isNullable (columnNumber); }

4. Kretanje kroz Postavi rezultat

Kad dobijemo Postavi rezultat, položaj kursora je ispred prvog retka. Štoviše, prema zadanim postavkama Postavi rezultat kreće se samo u smjeru naprijed. Ali, možemo koristiti pomičnu Postavi rezultat za ostale mogućnosti navigacije.

U ovom ćemo odjeljku razgovarati o raznim navigacijskim opcijama.

4.1. Postavi rezultat Vrste

Postavi rezultat type označava kako ćemo se kretati kroz skup podataka:

  • TIP_FORWARD_ONLY - zadana opcija, u kojoj se kursor pomiče od početka do kraja
  • TIP_SCROLL_INSENSITIVE - naš se kursor može kretati kroz skup podataka u smjeru naprijed i natrag; ako postoje promjene osnovnih podataka tijekom kretanja kroz skup podataka, oni se zanemaruju; skup podataka sadrži podatke od trenutka kada upit baze podataka vraća rezultat
  • TIP_SCROLL_SENSITIVE - slično tipu neosjetljivom na pomicanje, međutim za taj tip skup podataka odmah odražava sve promjene osnovnih podataka

Ne podržavaju sve baze podataka sve Postavi rezultat vrste. Dakle, provjerimo je li vrsta podržana pomoću supportsResultSetType na naš DatabaseMetaData objekt:

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

4.2. Skup rezultata koji se može pomicati

Da biste dobili pomičnu Postavi rezultat, moramo prenijeti neke dodatne parametre tijekom pripreme Izjava.

Na primjer, dobili bismo pomičnu Postavi rezultat korištenjem bilo kojeg TIP_SCROLL_INSENSITIVE ili TIP_SCROLL_SENSITIVE kao Postavi rezultat tip:

PreparedStatement pstmt = dbConnection.prepareStatement ("odaberi * od zaposlenika", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); RezultatSkup rs = pstmt.executeQuery (); 

4.3. Opcije navigacije

Za pomicanje možemo koristiti bilo koju od dolje navedenih opcija Postavi rezultat:

  • Sljedeći() - nastavlja se na sljedeći red sa trenutne pozicije
  • prethodni () - prelazak na prethodni red
  • prvi () - prelazi na prvi red datoteke Postavi rezultat
  • posljednji() - skače na zadnji red
  • beforeFirst () - kreće na start; pozivajući Sljedeći() na naš Postavi rezultat nakon poziva ove metode vraća prvi redak iz našeg Postavi rezultat
  • afterLast () - skokovi do kraja; pozivajući prethodni () na našem ResultSet-u nakon izvršavanja ove metode vraća zadnji redak iz našeg Postavi rezultat
  • relativno (int numOfRows) - idi naprijed ili natrag iz trenutne pozicije za numOfRows
  • apsolutni (int rowNumber) - skoči na redBroj specificirano

Pogledajmo nekoliko primjera:

PreparedStatement pstmt = dbConnection.prepareStatement ("odaberi * od zaposlenika", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); RezultatSkup rs = pstmt.executeQuery (); while (rs.next ()) {// prelistavanje rezultata od prvog do zadnjeg} rs.beforeFirst (); // preskače natrag na početnu točku, prije prvog reda rs.afterLast (); // preskače na kraj skupa rezultata rs.first (); // prelazi na prvi red rs.last (); // ide na zadnji red rs.absolute (2); // preskače na 2. red rs.relative (-1); // skok na prethodni redak rs.relative (2); // skače naprijed za dva retka dok (rs.previous ()) {// prelazi iz trenutnog retka u prvi redak u nazadnom smjeru} 

4.4. Postavi rezultat Brojanje redova

Iskoristimo getRow () da bismo dobili trenutni broj retka našeg Postavi rezultat.

Prvo ćemo prijeći na zadnji redak Postavi rezultat a zatim upotrijebite getRow () da biste dobili broj zapisa:

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

5. Ažuriranje podataka u a Postavi rezultat

Prema zadanim postavkama Postavi rezultat je samo za čitanje. Međutim, možemo koristiti ažuriranje Postavi rezultat za umetanje, ažuriranje i brisanje redaka.

5.1. Postavi rezultat Konkurencija

Način istodobnosti pokazuje je li naš Postavi rezultat može ažurirati podatke.

The CONCUR_READ_ONLY opcija je zadana i trebala bi se koristiti ako ne trebamo ažurirati podatke pomoću našeg Postavi rezultat.

Međutim, ako trebamo ažurirati podatke u našem Postavi rezultat, onda CONCUR_UPDATABLE treba koristiti opciju.

Ne podržavaju sve baze podataka sve paralelne načine rada za sve Postavi rezultat vrste. Stoga moramo provjeriti podržavaju li željeni tip i način istodobnosti pomoću supportsResultSetConcurrency () metoda:

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

5.2. Dobivanje ažuriranja Postavi rezultat

Da biste dobili ažuriranje Postavi rezultat, moramo pripremiti dodatni parametar kada pripremamo Izjava. Za to, iskoristimo CONCUR_UPDATABLE kao treći parametar prilikom izrade iskaza:

PreparedStatement pstmt = dbConnection.prepareStatement ("odaberi * od zaposlenika", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); RezultatSkup rs = pstmt.executeQuery ();

5.3. Ažuriranje retka

U ovom ćemo odjeljku ažurirati red pomoću ažuriranja Postavi rezultat stvoren u prethodnom odjeljku.

Podatke možemo ažurirati u nizu pozivima updateX () metode, prosljeđivanje imena i vrijednosti stupaca radi ažuriranja. Umjesto datoteke možemo koristiti bilo koji podržani tip podataka x u updateX () metoda.

Ažurirajmo "plaća" stupac koji je tipa dvostruko:

rs.updateDouble ("plaća", 1100,0);

Imajte na umu da ovo samo ažurira podatke u Postavi rezultat, ali izmjene još nisu spremljene natrag u bazu podataka.

Napokon, nazovimo updateRow () do spremite ažuriranja u bazu podataka:

rs.updateRow (); 

Umjesto imena stupaca, indeks stupaca možemo proslijediti na updateX () metode. To je slično korištenju indeksa stupca za dobivanje vrijednosti pomoću getX () metode. Prosljeđivanje ili imena stupca ili indeksa u updateX () metode daju isti rezultat:

rs.updateDouble (4, 1100,0); rs.updateRow (); 

5.4. Umetanje reda

Sad, umetnimo novi red pomoću našeg ažuriranja Postavi rezultat.

Prvo ćemo upotrijebiti moveToInsertRow () za pomicanje kursora za umetanje novog retka:

rs.moveToInsertRow ();

Dalje, moramo nazvati updateX () metode za dodavanje podataka u redak. Moramo pružiti podatke za sve stupce u tablici baze podataka. Ako ne pružamo podatke za svaki stupac, tada se koristi zadana vrijednost stupca:

rs.updateString ("ime", "Venkat"); rs.updateString ("pozicija", "DBA"); rs.updateDouble ("plaća", 925,0);

Onda, nazovimo insertRow () za umetanje novog retka u bazu podataka:

rs.insertRow ();

Napokon, poslužimo se moveToCurrentRow (). To će položaj kursora vratiti na redak u kojem smo bili prije nego što smo započeli s umetanjem novog retka pomoću moveToInsertRow () metoda:

rs.moveToCurrentRow ();

5.5. Brisanje retka

U ovom ćemo odjeljku izbrisati redak pomoću našeg ažuriranja Postavi rezultat.

Prvo ćemo prijeći na redak koji želimo izbrisati. Tada ćemo nazvati deleteRow () metoda za brisanje trenutnog retka:

rs.apsolutni (2); rs.deleteRow ();

6. Držanje

Držljivost određuje hoće li naša Postavi rezultat bit će otvoren ili zatvoren na kraju transakcije baze podataka.

6.1. Vrste zadržavanja

Koristiti CLOSE_CURSORS_AT_COMMIT ako je Postavi rezultat nije potreban nakon izvršenja transakcije.

Koristiti HOLD_CURSORS_OVER_COMMIT stvoriti zadržavanje Postavi rezultat. Držač Postavi rezultat nije zatvoren ni nakon što je izvršena transakcija baze podataka.

Ne podržavaju sve baze podataka sve vrste zadržavanja.

Pa, krenimo provjerite je li podržana vrsta zadržavanja koristeći supportsResultSetHoldability () na naš DatabaseMetaData objekt. Zatim ćemo dobiti zadanu zadržavanje baze podataka pomoću getResultSetHoldability ():

boolean isCloseCursorSupported = dbmd.supportsResultSetHoldability (ResultSet.CLOSE_CURSORS_AT_COMMIT); boolean isOpenCursorSupported = dbmd.supportsResultSetHoldability (ResultSet.HOLD_CURSORS_OVER_COMMIT); logička defaultHoldability = dbmd.getResultSetHoldability ();

6.2. Držati se Postavi rezultat

Da biste stvorili zadržavanje Postavi rezultat, moramo navesti zadržavanje tip kao zadnji parametar tijekom stvaranja a Izjava. Ovaj je parametar naveden nakon paralelnog načina rada.

Imajte na umu da ako koristimo Microsoft SQL Server (MSSQL), moramo postaviti sposobnost zadržavanja na vezi s bazom podataka, a ne na Postavi rezultat:

dbConnection.setHoldability (ResultSet.HOLD_CURSORS_OVER_COMMIT);

Pogledajmo ovo na djelu. Prvo, izradimo a Izjava, postavljanje zadržavanja na HOLD_CURSORS_OVER_COMMIT:

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

Sada, ažurirajmo red dok dohvaćamo podatke. Ovo je slično primjeru ažuriranja o kojem smo ranije raspravljali, osim što ćemo nastaviti ponavljati Postavi rezultat nakon predavanja transakcije ažuriranja u bazu podataka. Ovo dobro funkcionira i na MySQL i MSSQL bazama podataka:

dbConnection.setAutoCommit (netačno); ResultSet rs = pstmt.executeQuery ("odaberi * od zaposlenika"); while (rs.next ()) {if (rs.getString ("name"). equalsIgnoreCase ("john")) {rs.updateString ("name", "John Doe"); rs.updateRow (); dbConnection.commit (); }} rs.last (); 

Vrijedno je napomenuti da MySQL podržava samo HOLD_CURSORS_OVER_COMMIT. Dakle, čak i ako koristimo CLOSE_CURSORS_AT_COMMIT, bit će zanemareno.

Podrška baze podataka MSSQL CLOSE_CURSORS_AT_COMMIT. To znači da Postavi rezultat bit će zatvorena kad izvršimo transakciju. Kao rezultat toga, pokušaj pristupa Postavi rezultat nakon izvršavanja transakcije dolazi do pogreške "Pokazivač nije otvoren". Stoga ne možemo dohvatiti daljnje zapise iz Postavi rezultat.

7. Veličina dohvata

Tipično, prilikom učitavanja podataka u Postavi rezultat, pokretači baze podataka odlučuju o broju redaka koje će dohvatiti iz baze podataka. Na MySQL bazi podataka, na primjer, Postavi rezultat normalno učitava sve zapise u memoriju odjednom.

Međutim, ponekad ćemo možda morati imati posla s velikim brojem zapisa koji neće stati u našu JVM memoriju. U ovom slučaju možemo koristiti svojstvo veličine dohvaćanja bilo na našem Izjava ili Postavi rezultat objekata za ograničavanje broja prvobitno vraćenih zapisa.

Kad god su potrebni dodatni rezultati, Postavi rezultat dohvaća još jednu seriju zapisa iz baze podataka. Pomoću svojstva veličine dohvaćanja možemo pružiti prijedlog pokretaču baze podataka o broju redaka koje treba dohvatiti po putovanju baze podataka. Veličina dohvata koju odredimo primijenit će se na sljedeća putovanja baze podataka.

Ako ne odredimo veličinu dohvata za naš Postavi rezultat, zatim veličina dohvata datoteke Izjava koristi se. Ako ne odredimo veličinu dohvata ni za jedan Izjava ili Postavi rezultat, tada se koristi zadana baza podataka.

7.1. Korištenje veličine dohvata na Izjava

Pogledajmo sada veličinu dohvata Izjava u akciji. Postavit ćemo veličinu dohvata datoteke Izjava do 10 zapisa. Ako naš upit vrati 100 zapisa, tada će biti 10 povratnih putovanja do baze podataka, svaki put se učitava 10 zapisa:

PreparedStatement pstmt = dbConnection.prepareStatement ("odaberi * od zaposlenika", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); pstmt.setFetchSize (10); RezultatSkup rs = pstmt.executeQuery (); while (rs.next ()) {// prelistavanje kroz rezultat}

7.2. Korištenje veličine dohvata na Postavi rezultat

Promijenimo sada veličinu dohvata u našem prethodnom primjeru pomoću Postavi rezultat.

Prvo ćemo upotrijebiti veličinu dohvata na našem Izjava. To omogućuje našem Postavi rezultat za prvo učitavanje 10 zapisa nakon izvršavanja upita.

Zatim ćemo izmijeniti veličinu dohvata na Postavi rezultat. Ovo će nadjačati veličinu dohvata koju smo ranije naveli na našoj Izjava. Dakle, sva sljedeća putovanja učitat će 20 zapisa dok se svi unosi ne učitaju.

Kao rezultat, održat će se samo 6 putovanja baze podataka radi učitavanja svih zapisa:

PreparedStatement pstmt = dbConnection.prepareStatement ("odaberi * od zaposlenika", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); pstmt.setFetchSize (10); RezultatSkup rs = pstmt.executeQuery (); rs.setFetchSize (20); while (rs.next ()) {// prelistavanje kroz rezultat}

Na kraju ćemo vidjeti kako izmijeniti veličinu dohvata datoteke Postavi rezultat dok ponavlja rezultate.

Slično prethodnom primjeru, prvo ćemo postaviti veličinu dohvata na 10 na našem Izjava. Dakle, naša prva 3 putovanja u bazu podataka učitat će 10 zapisa po svakom putovanju.

A zatim ćemo izmijeniti veličinu dohvata na našem Postavi rezultat do 20 tijekom čitanja 30. zapisa. Dakle, sljedeća 4 putovanja učitat će 20 zapisa po svakom putovanju.

Stoga će nam trebati 7 putovanja u bazu podataka da bismo učitali svih 100 zapisa:

PreparedStatement pstmt = dbConnection.prepareStatement ("odaberi * od zaposlenika", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); pstmt.setFetchSize (10); RezultatSkup rs = pstmt.executeQuery (); int rowCount = 0; while (rs.next ()) {// prelistavanje skupa rezultata if (rowCount == 30) {rs.setFetchSize (20); } rowCount ++; }

8. Zaključak

U ovom smo članku vidjeli kako se koristi Postavi rezultat API za dohvaćanje i ažuriranje podataka iz baze podataka. Nekoliko naprednih značajki o kojima smo razgovarali ovise o bazi podataka koju koristimo. Stoga moramo provjeriti podršku za te značajke prije nego što ih upotrijebimo.

Kao i uvijek, kôd je dostupan na GitHub-u.