Uvod u JDBC

Java Top

Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:

>> PROVJERITE TEČAJ

1. Pregled

U ovom ćemo članku pogledati JDBC (Java Database Connectivity) koji je API za povezivanje i izvršavanje upita u bazi podataka.

JDBC može raditi s bilo kojom bazom podataka sve dok su osigurani odgovarajući pokretački programi.

2. JDBC upravljački programi

JDBC pogonitelj je JDBC API implementacija koja se koristi za povezivanje s određenom vrstom baze podataka. Postoji nekoliko vrsta JDBC pokretačkih programa:

  • Tip 1 - sadrži mapiranje na drugi API za pristup podacima; primjer za to je upravljački program JDBC-ODBC
  • Tip 2 - je implementacija koja koristi biblioteke ciljne baze podataka na strani klijenta; naziva se i pokretačkim API-jem
  • Tip 3 - koristi međuopreme za pretvaranje JDBC poziva u pozive specifične za bazu podataka; poznat i kao pokretač mrežnog protokola
  • Tip 4 - izravno se povežite s bazom podataka pretvaranjem JDBC poziva u pozive specifične za bazu podataka; poznati kao pokretači protokola baze podataka ili tanki pokretački programi,

Najčešće korišteni tip je tip 4, jer ima prednost što je neovisno o platformi. Izravno povezivanje s poslužiteljem baze podataka pruža bolje performanse u usporedbi s drugim vrstama. Loša strana ove vrste pokretačkog programa je što je specifičan za bazu podataka - s obzirom da svaka baza podataka ima svoj specifični protokol.

3. Povezivanje s bazom podataka

Da bismo se povezali s bazom podataka, jednostavno moramo inicijalizirati upravljački program i otvoriti vezu s bazom podataka.

3.1. Registriranje upravljačkog programa

Za naš ćemo primjer upotrijebiti upravljački program protokola baze podataka tipa 4.

Budući da koristimo MySQL bazu podataka, trebamo mysql-konektor-java ovisnost:

 mysql mysql-konektor-java 6.0.6 

Dalje, registrirajmo upravljački program pomoću Class.forName () metoda koja dinamički učitava klasu vozača:

Class.forName ("com.mysql.cj.jdbc.Driver");

U starijim verzijama JDBC-a, prije dobivanja veze, prvo smo morali inicijalizirati JDBC upravljački program pozivanjem Razred.zaIme metoda. Od JDBC 4.0, svi se upravljački programi koji se nalaze u stazi predavanja automatski učitavaju. Stoga nam ovo neće trebati Razred.zaIme dio u modernim sredinama.

3.2. Stvaranje veze

Da bismo otvorili vezu, možemo koristiti getConnection () metoda DriverManager razred. Ova metoda zahtijeva URL veze Niz parametar:

probajte (Connection con = DriverManager .getConnection ("jdbc: mysql: // localhost: 3306 / myDb", "user1", "pass")) {// ovdje koristite con}

Budući da je Veza je AutoCloseable resurs, trebali bismo ga koristiti unutar a pokušajte s resursima blok.

Sintaksa URL-a veze ovisi o vrsti baze podataka koja se koristi. Pogledajmo nekoliko primjera:

jdbc: mysql: // localhost: 3306 / myDb? user = user1 & password = pass
jdbc: postgresql: // localhost / myDb
jdbc: hsqldb: mem: myDb

Za povezivanje na navedeno myDb baze podataka, morat ćemo stvoriti bazu podataka i korisnika te dodati odobreni potreban pristup:

IZRADI BAZU PODATAKA myDb; STVORI KORISNIKA 'user1' IDENTIFIED BY 'pass'; DODATI SVE na myDb. * 'User1';

4. Izvršavanje SQL izjava

Pošaljite SQL upute u bazu podataka, možemo koristiti primjerke tipa Izjava, Pripremljena izjava, ili CallableStatement, koje možemo dobiti pomoću Veza objekt.

4.1. Izjava

The Izjava sučelje sadrži osnovne funkcije za izvršavanje SQL naredbi.

Prvo, izradimo a Izjava objekt:

probajte (Izjava stmt = con.createStatement ()) {// ovdje koristite stmt}

Opet, trebali bismo surađivati Izjavas unutar a pokušajte s resursima blok za automatsko upravljanje resursima.

U svakom slučaju, izvršavanje SQL uputa može se izvršiti pomoću tri metode:

  • executeQuery () za upute SELECT
  • executeUpdate () za ažuriranje podataka ili strukture baze podataka
  • izvršiti() može se koristiti za oba navedena slučaja kada je rezultat nepoznat

Iskoristimo izvršiti() metoda za dodavanje a studenti tablica u našoj bazi podataka:

String tableSql = "IZRADI TABLU AKO NE POSTOJI zaposlenici" + "(emp_id int PRIMARNI KLJUČ AUTO_INCREMENT, ime varchar (30)," + "pozicija varchar (30), plaća dvostruka)"; stmt.execute (tableSql);

Kada koristite izvršiti() metoda za ažuriranje podataka, a zatim stmt.getUpdateCount () metoda vraća broj zahvaćenih redaka.

Ako je rezultat 0, tada to nije utjecao niti na jedan redak, ili je to bila naredba za ažuriranje strukture baze podataka.

Ako je vrijednost -1, tada je naredba bila SELECT upit; tada možemo dobiti rezultat pomoću stmt.getResultSet ().

Dalje, dodajmo zapis u našu tablicu pomoću executeUpdate () metoda:

String insertSql = "INSERT INTO zaposlenika (ime, pozicija, plaća)" + "VRIJEDNOSTI ('john', 'programer', 2000)"; stmt.executeUpdate (insertSql);

Metoda vraća broj zahvaćenih redaka za naredbu koja ažurira retke ili 0 za naredbu koja ažurira strukturu baze podataka.

Zapise možemo dohvatiti iz tablice pomoću executeQuery () metoda koja vraća objekt tipa Postavi rezultat:

String selectSql = "SELECT * FROM zaposlenika"; probajte (ResultSet resultSet = stmt.executeQuery (selectSql)) {// ovdje upotrijebite resultSet}

Trebali bismo zatvoriti Postavi rezultat slučajevi nakon upotrebe. Inače, osnovni kursor možemo držati otvoren mnogo dulje vrijeme nego što se očekivalo. Da biste to učinili, preporučuje se upotreba a pokušajte s resursima blok, kao u našem primjeru gore.

4.2. PreparedStatement

PreparedStatement objekti sadrže prekompajlirane SQL sekvence. Mogu imati jedan ili više parametara označenih upitnikom.

Stvorimo a PreparedStatement koji ažurira zapise u zaposlenici tablica na temelju zadanih parametara:

String updatePositionSql = "AŽURIRANJE zaposlenika SET položaj =? GDJE emp_id =?"; probajte (PreparedStatement pstmt = con.prepareStatement (updatePositionSql)) {// ovdje koristite pstmt}

Da biste dodali parametre u PreparedStatement, možemo koristiti jednostavne postavljače - setX () - gdje je X vrsta parametra, a argumenti metode su redoslijed i vrijednost parametra:

pstmt.setString (1, "vodeći programer"); pstmt.setInt (2, 1);

Izjava se izvršava jednom od iste tri prethodno opisane metode: executeQuery (), executeUpdate (), execute () bez SQL-a Niz parametar:

int redoviAffected = pstmt.executeUpdate ();

4.3. CallableStatement

The CallableStatement sučelje omogućuje pozivanje pohranjenih procedura.

Za stvaranje a CallableStatement objekt, možemo koristiti pripremiti poziv () metoda Veza:

Niz pripremljenSql = "{poziv insertEeeeeeee? (?,?,?,?)}"; probajte (CallableStatement cstmt = con.prepareCall (PrepaSql)) {// ovdje upotrijebite cstmt}

Postavljanje vrijednosti ulaznih parametara za pohranjenu proceduru vrši se kao u PreparedStatement sučelje, koristeći setX () metode:

cstmt.setString (2, "ana"); cstmt.setString (3, "tester"); cstmt.setDouble (4, 2000);

Ako pohranjena procedura ima izlazne parametre, trebamo ih dodati pomoću registerOutParameter () metoda:

cstmt.registerOutParameter (1, tipovi.INTEGER);

Zatim izvršimo izraz i dohvatimo vraćenu vrijednost pomoću odgovarajućeg getX () metoda:

cstmt.execute (); int novi_id = cstmt.getInt (1);

Na primjer, da bismo radili, moramo stvoriti pohranjenu proceduru u našoj MySql bazi podataka:

graničnik // STVORI POSTUPAK insertE Employee (OUT emp_id int, IN emp_name varchar (30), IN pozicija varchar (30), IN plaća dvostruko) POČINJU UMJERATI u zaposlenike (ime, pozicija, plaća) VRIJEDNOSTI (emp_name, pozicija, plaća); POSTAVITE emp_id = LAST_INSERT_ID (); END // graničnik;

The umetakZaposlenik gore navedeni postupak umetnut će novi zapis u zaposlenici tablici pomoću zadanih parametara i vratite ID novog zapisa u emp_id parametar out.

Da bi mogao pokrenuti pohranjenu proceduru s Jave, korisnik veze mora imati pristup metapodacima pohranjene procedure. To se može postići davanjem prava korisniku na sve pohranjene procedure u svim bazama podataka:

DODATI SVE NA mysql.proc 'user1';

Alternativno, možemo otvoriti vezu s posjedom noAccessToProcedureBodies postavljen pravi:

con = DriverManager.getConnection ("jdbc: mysql: // localhost: 3306 / myDb? noAccessToProcedureBodies = true", "user1", "pass");

To će obavijestiti JDBC API da korisnik nema prava čitati metapodatke postupka, tako da će stvoriti sve parametre kao INOUT Niz parametri.

5. Raščlanjivanje rezultata upita

Nakon izvršavanja upita, rezultat je predstavljen s Postavi rezultat objekt koji ima strukturu sličnu tablici, s linijama i stupcima.

5.1. Postavi rezultat Sučelje

The Postavi rezultat koristi Sljedeći() metoda za prelazak na sljedeći redak.

Prvo napravimo Zaposlenik razred za pohranu naših preuzetih zapisa:

zaposlenik u javnoj klasi {private int id; privatni naziv niza; privatni položaj gudača; privatna dvostruka plaća; // standardni konstruktor, getteri, postavljači}

Dalje, krenimo Postavi rezultat i stvoriti Zaposlenik objekt za svaki zapis:

String selectSql = "SELECT * FROM zaposlenika"; probajte (ResultSet resultSet = stmt.executeQuery (selectSql)) {Popis zaposlenika = novi ArrayList (); while (resultSet.next ()) {Employee emp = novi zaposlenik (); emp.setId (resultSet.getInt ("emp_id")); emp.setName (resultSet.getString ("ime")); emp.setPosition (resultSet.getString ("položaj")); emp.setSalary (resultSet.getDouble ("plaća")); zaposlenici.add (emp); }}

Dohvaćanje vrijednosti za svaku ćeliju tablice može se izvršiti pomoću metoda tipa getX () gdje X predstavlja vrstu podataka o ćeliji.

The getX () metode mogu se koristiti s int parametar koji predstavlja redoslijed ćelije ili a Niz parametar koji predstavlja ime stupca. Potonja opcija je poželjnija u slučaju da promijenimo redoslijed stupaca u upitu.

5.2. Ažurirano Postavi rezultat

Implicitno, a Postavi rezultat objekt se može premjestiti samo naprijed i ne može se mijenjati.

Ako želimo koristiti Postavi rezultat da bismo ažurirali podatke i prešli ih u oba smjera, moramo stvoriti Izjava objekt s dodatnim parametrima:

stmt = con.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

Za navigaciju ovom vrstom Postavi rezultat, možemo se poslužiti jednom od metoda:

  • first (), last (), beforeFirst (), beforeLast () - za pomicanje u prvi ili zadnji redak a Postavi rezultat ili na crtu prije ovih
  • sljedeći (), prethodni () - za kretanje naprijed i natrag u Postavi rezultat
  • getRow () - za dobivanje trenutnog broja reda
  • moveToInsertRow (), moveToCurrentRow () - za pomicanje u novi prazan redak za umetanje i povratak u trenutni ako je u novom redu
  • apsolutno (int redak) - za pomicanje u navedeni redak
  • relativno (int nrRows) - za pomicanje kursora na zadani broj redaka

Ažuriranje Postavi rezultat može se izvršiti pomoću metoda s formatom updateX () gdje je X vrsta ćelijskih podataka. Ove metode samo ažuriraju Postavi rezultat objekt, a ne tablice baze podataka.

Ustrajati u Postavi rezultat promjene baze podataka, moramo dalje koristiti jednu od metoda:

  • updateRow () - da se nastave promjene trenutnog retka baze podataka
  • insertRow (), deleteRow () - za dodavanje novog retka ili brisanje trenutnog iz baze podataka
  • refreshRow () - za osvježavanje Postavi rezultat uz bilo kakve promjene u bazi podataka
  • cancelRowUpdates () - za poništavanje promjena u trenutnom retku

Pogledajmo primjer korištenja nekih od ovih metoda ažuriranjem podataka u zaposlenikova stol:

try (Statement updatableStmt = con.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE))) {try (ResultSet updatableResultSet = updatableStmt.executeQuery (selectSql)) {updatableResultSetsertResultSet UpdatableResultSet.updateString ("ime", "oznaka"); UpdatableResultSet.updateString ("pozicija", "analitičar"); UpdatableResultSet.updateDouble ("plaća", 2000); UpdatableResultSet.insertRow (); }}

6. Raščlanjivanje metapodataka

JDBC API omogućuje traženje podataka o bazi podataka, koji se nazivaju metapodaci.

6.1. Baza podatakaMetadata

The Baza podatakaMetadata Sučelje se može koristiti za dobivanje općih informacija o bazi podataka, poput tablica, pohranjenih procedura ili SQL dijalekta.

Kratko ćemo pogledati kako možemo doći do podataka na tablicama baze podataka:

DatabaseMetaData dbmd = con.getMetaData (); ResultSet tablesResultSet = dbmd.getTables (null, null, "%", null); while (tablesResultSet.next ()) {LOG.info (tablesResultSet.getString ("TABLE_NAME")); }

6.2. ResultSetMetadata

Ovo sučelje može se koristiti za pronalaženje podataka o određenom Postavi rezultat, kao što su broj i naziv njegovih stupaca:

ResultSetMetaData rsmd = rs.getMetaData (); int nrColumns = rsmd.getColumnCount (); IntStream.range (1, nrColumns) .forEach (i -> {try {LOG.info (rsmd.getColumnName (i));} catch (SQLException e) {e.printStackTrace ();}});

7. Rukovanje transakcijama

Prema zadanim se postavkama svaki SQL izraz urezuje odmah nakon dovršenja. Međutim, to je također moguće programski kontrolirati transakcije.

To može biti potrebno u slučajevima kada želimo sačuvati dosljednost podataka, na primjer kada transakciju želimo izvršiti samo ako je prethodna uspješno dovršena.

Prvo, moramo postaviti autoCommit vlasništvo Veza do lažno, a zatim upotrijebite počiniti() i vraćanje () metode za kontrolu transakcije.

Dodajmo drugu izjavu o ažuriranju za plaća stupac iza zaposlenika položaj ažurirati stupac i zamotati ih oboje u transakciju. Na ovaj će se način plaća ažurirati samo ako je pozicija uspješno ažurirana:

String updatePositionSql = "AŽURIRANJE zaposlenika POSTAVI položaj =? GDJE emp_id =?"; PreparedStatement pstmt = con.prepareStatement (updatePositionSql); pstmt.setString (1, "vodeći programer"); pstmt.setInt (2, 1); String updateSalarySql = "AŽURIRAJ zaposlenike PLAĆA =? GDJE emp_id =?"; PreparedStatement pstmt2 = con.prepareStatement (updateSalarySql); pstmt.setDouble (1, 3000); pstmt.setInt (2, 1); logički autoCommit = con.getAutoCommit (); pokušajte {con.setAutoCommit (false); pstmt.executeUpdate (); pstmt2.executeUpdate (); con.commit (); } catch (SQLException exc) {con.rollback (); } napokon {con.setAutoCommit (autoCommit); }

Radi kratkoće izostavljamo pokušajte s resursima blokovi ovdje.

8. Zatvaranje resursa

Kad ga više ne koristimo, moramo zatvoriti vezu kako bismo oslobodili resurse baze podataka.

To možemo učiniti pomoću Zatvoriti() API:

con.close ();

Međutim, ako resurs koristimo u a pokušajte s resursima blok, ne trebamo zvati Zatvoriti() metoda izričito, kao pokušajte s resursima blok to automatski radi za nas.

Isto vrijedi i za Izjavas, PreparedStatements, CallableStatements, i Postavi rezultats.

9. Zaključak

U ovom smo tutorijalu pogledali osnove rada s JDBC API-jem.

Kao i uvijek, puni izvorni kod primjera može se naći na GitHubu.

Dno Java

Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:

>> PROVJERITE TEČAJ