Esittely latautuu. Ole hyvä ja odota

Esittely latautuu. Ole hyvä ja odota

Samankaltaiset esitykset


Esitys aiheesta: ""— Esityksen transkriptio:

113 4.3. Tietokantojen ohjelmointirajapinnat
Engl. API (Application Programming Interface). Ohj.kielen täydennys moduuli-/luokkakirjastoilla SQL/CLI (Call-Level Interface), osa SQL-standardia vuodesta 2003. Tunnetuimpia rajapintoja: ODBC (Open DataBase Connectivity): SQL/CLI-pohjainen, Microsoftin kehittämä, yleinen C, C++, C# ja Visual Basic –kielten yhteydessä. JDBC (‘Java DataBase Connectivity’): Sun Micro-systemsin piirissä kehitetty API-kirjasto Javalle. 4-3-OhjRajapinnat Teuhola 2012

114 4-3-OhjRajapinnat Teuhola 2012
JDBC: Yleistä JDBC on Javan luokka-/rajapintakirjastomääritys, joka mahdollistaa SQL-lauseiden suorituksen Javasta käsin (lauseet metodien parametreina). Vastaa dynaamista, sulautettua SQL:ää. Ero SQLJ:hin: JDBC ei ole kielen laajennus, joten standardi Java-kääntäjä riittää. Hyvin tuettu (‘teollisuusstandardi’) Javan etu: siirrettävyys (portability). JDBC:tä käyttävä ohjelma on lähes riippumaton siitä, mikä tietokantajärjestelmä on käytössä (voidaan vaihtaa) 4-3-OhjRajapinnat Teuhola 2012

115 4-3-OhjRajapinnat Teuhola 2012
JDBC-ajuri JDBC-API toimii sovellusohjelmien rajapintana. Yhteydet tietokantaan hoitaa JDBC-ajuri (driver). Kuhunkin tietokantajärjestelmään on oma ajurinsa; saatavana järjestelmän toimittajalta, ks. esim. Ajuri on jar-paketti (esim. postgresql.jar), joka sijoitetaan haluttuun hakemistopolkuun. Polku pitää määritellä CLASSPATH-ympäristömuuttu-jassa. 4-3-OhjRajapinnat Teuhola 2012

116 Asiakas/palvelin-arkkitehtuuri
Tietokannan hallintajärjestelmä JDBC-ajuri Java-ohjelma Tietokanta Asiakas Palvelin 4-3-OhjRajapinnat Teuhola 2012

117 JDBC:n mukaanotto sovellusohjelmaan
JDBC-pakkaukset (kuuluvat J2SE:hen): import java.sql.*; // Perus-JDBC import javax.sql.*; // Laajennuksia, JDBC 2.0, 3.0, 4.0 DriverManager pitää kirjaa ajureista, joita samassa sovelluksessa voi olla useita. Ajuri pitää ladata ja rekisteröidä Driver Managerille esim. seuraavasti: Class.forName(“org.postgresql.Driver”) missä ajurin tiedostopolku on em. jar-paketissa. 4-3-OhjRajapinnat Teuhola 2012

118 Yksinkertaisen JDBC-sovelluksen vaiheet
Ladataan ajuri (vrt. ed.) Muodostetaan yhteys (Connection) tietokantaan Luodaan SQL-lause (Statement) Suoritetaan lause Käsitellään mahdollinen tulosjoukko (ResultSet), tai siepataan ja käsitellään poikkeukset. Toistetaan kohtia 3-5 tarpeen mukaan Suljetaan tietokantaoliot (tulosjoukko, yhteys) 4-3-OhjRajapinnat Teuhola 2012

119 Yhteyden muodostus tietokantaan
Tarvittava metodi löytyy DriverManager-luokasta: DriverManager.getConnection(<url>, <käyttäjä>, <salasana>); missä <url> on muotoa “jdbc:<ajuri>:<datalähde>”, esim. "jdbc:postgresql://kanta.cs.utu.fi:5432/company“ 4-3-OhjRajapinnat Teuhola 2012

120 4-3-OhjRajapinnat Teuhola 2012
SQL-lauseet Lause-olioita (Statement-rajapinta) tarvitaan edustamaan SQL-lauseita. Statement-rajapinnassa on mm. metodeita SQL-lauseen suorittamiseksi. Tärkeä alirajapinta: PreparedStatement: SQL-lause jäsennetään, tarkistetaan ja käännetään vain kerran, mutta suoritetaan ehkä toistuvasti (tehokkaampi). 4-3-OhjRajapinnat Teuhola 2012

121 Statement-olion luonti ja suoritus
Luonti Connection-olion createStatement-metodilla. Suoritus executeQuery- tai executeUpdate-metodilla lauseen tyypistä riippuen. Kyselyn tulos on tyyppiä ResultSet. Esimerkki: Connection c = DriverManager.getConnection(url, user, pwd); Statement st = c.createStatement(); ResultSet res = st.executeQuery( "SELECT Ano, Animi FROM Asiakas;"); 4-3-OhjRajapinnat Teuhola 2012

122 Statement-olion luonti ja suoritus (jatk.)
ResultSet-olio (esimerkissä res) edustaa 2-ulotteista taulukkoa, jota voidaan kulkea iteraattorin tapaan rivi kerrallaan (vrt. SQLJ:n ‘iterator’). Ensin res osoittaa 1. rivin ‘edelle’, josta res.next()-metodilla saadaan 1., 2., … rivi, kunnes res==NULL. Yksittäiset rivin alkiot saadaan res.getxxx(sarake)-metodeilla, missä ‘xxx’ on alkion tyyppi (getInt, getLong, getFloat, getDouble, getString, getBoolean, getDate, getTime, getObject, ym.). ‘Sarake’ voidaan ilmaista joko järjestysnumerolla (1, 2, …) tai tulosattribuutin nimellä. 4-3-OhjRajapinnat Teuhola 2012

123 Statement-olion luonti ja suoritus (jatk.)
JDBC ei tee eroa 1- ja monirivisten tulos-taulukoiden välillä. Jos tuloksessa tiedetään olevan vain 1 rivi, silmukka voidaan välttää, mutta res.next():llä pitää siirtyä 1. riville. Poikkeuksista: JDBC-kutsut voivat nostaa mm. SQLException-poikkeuksia. Ne voidaan joko käsitellä (try … catch …) tai siirtää kutsujalle. 4-3-OhjRajapinnat Teuhola 2012

124 4-3-OhjRajapinnat Teuhola 2012
JDBC-esimerkki // Etsi annetun paikkakunnan henkilöt relaatiosta // Asiakas (Ano, Animi, Paikka). // import java.io.*; import java.sql.*; class HaeAsiakkaat { public static void main(String args[]) throws SQLException, IOException { try { Class.forName (“org.postgresql.Driver”); } catch (ClassNotFoundException cnfe) { System.out.println(“Ajuria ei löydy!”); } // jatkuu seur. sivulla … 4-3-OhjRajapinnat Teuhola 2012

125 JDBC-esimerkki (jatk.)
String tunnus = prompt(“Anna käyttäjätunnus”); // Hoputemetodi String salasana = prompt(“Anna salasana”); Connection conn = DriverManager.getConnection( “jdbc:postgresql://host/tietokanta”, tunnus, salasana); String paikkakunta = prompt(“Anna paikkakunta”); String kys = “SELECT Ano, Animi FROM Asiakas ” “WHERE Paikka = ‘” + paikkakunta + “’;”; Statement stmt = conn.createStatement(); ResultSet res = stmt.executeQuery(kys); while (res.next()) { int no = res.getInt(1); String nimi = res.getString(2); System.out.println(no + “ “ + nimi); } res.close(); conn.close(); } } 4-3-OhjRajapinnat Teuhola 2012

126 JDBC: SQL-lauseen toistuva suoritus
Lause kannattaa jäsentää ja optimoida vain kerran ja käyttää ‘käännettyä’ versiota toistuvissa suorituksissa. PreparedStatement (‘valmisteltu’ lause) on tällainen: perii Statement-rajapinnan, luonti Connection-olion prepareStatement()-metodilla, parametrina SQL-lause. Mutta: Yleensä eri suorituskerroilla on jotain eroa; SQL-lause on voitava parametrisoida. 4-3-OhjRajapinnat Teuhola 2012

127 PreparedStatement: SQL-lauseen parametrisointi
JDBC-ratkaisu: SQL-lauseeseen sijoitetaan tuntemattomien osien kohdalle ‘?’-merkkejä, jotka voidaan eri kerroilla sitoa eri parametriarvoihin. ‘?’-parametrit ajatellaan numeroiduiksi 1, 2, … Parametrisointi rajoitettua; esim. FROM-osan relaationimiä ei voi parametrisoida. Parametrien asetus setxxx()-metodeilla (setInt, setFloat, setString, …) 4-3-OhjRajapinnat Teuhola 2012

128 “Etsi annettujen paikkakuntien asiakkaat”
// … Alkuosa kuten edellä String kys = “SELECT Ano, Animi FROM Asiakas ” “WHERE Paikka = ?;”; PreparedStatement ps = conn.prepareStatement(kys); String paikka = prompt(“Anna paikkakunta, lopuksi tyhjä”); while (!(paikka.equals(“”))) { System.out.println(“Paikkakunnan ” + paikka + “ asiakkaat”); ps.setString(1, paikka); ResultSet res = ps.executeQuery(); while (res.next()) { int no = res.getInt(1); String nimi = res.getString(2); System.out.println(no + “ “ + nimi); } res.close(); paikka = prompt(“Anna paikkakunta, lopuksi tyhjä”); } conn.close(); } } 4-3-OhjRajapinnat Teuhola 2012

129 JDBC: Päivityslauseet
Metodilla executeQuery() voidaan suorittaa vain SELECT-lauseita. Päivityslause suoritetaan käskyllä executeUpdate(), joka palauttaa päivitettyjen rivien määrän. 4-3-OhjRajapinnat Teuhola 2012

130 “Annetun valmistajan tuotteille annetun suuruinen alennus”
// Relaatioskeema: // Tuote (Tno, Tnimi, Valmistaja, Hinta) … String valm = prompt(“Anna valmistaja”); int ale = promptInt(“Anna alennusprosentti”); String paiv = “UPDATE Tuote “ “SET Hinta = Hinta*(100-” + ale + “)/100 “ “WHERE Valmistaja = ‘“ + valm + “’;”); int lkm = conn.executeUpdate(paiv); System.out.println(lkm + “ tuotetta halpeni”); … 4-3-OhjRajapinnat Teuhola 2012

131 Yleistetty ResultSet-rajapinta
Mahdollistaa monipuolisemman vierityksen (scroll): first(), last(), next(), previous(), absolute(int), relative(int) Mahdollistaa nykyistä ResultSet-riviä vastaavan tietokantarivin päivityksen. Vrt. SQLJ: #sql iterator … implements sqlj.runtime.ForUpdate Yleistetty tulosjoukko määritellään Statement-olion luonnin yhteydessä. 4-3-OhjRajapinnat Teuhola 2012

132 Yleistetty ResultSet-rajapinta (jatk.)
Lauseen luonti esim. Statement lause = conn.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); Lauseen suoritus esim.: ResultSet res = lause.executeQuery( "SELECT Ano, Animi, Paikka FROM Asiakas;"); Päivitys, esim. kolmanteen tulosriviin uusi paikka: res.absolute(3); // Siirtyminen 3. riville res.updateString(“Paikka", “Parainen"); // Uusi arvo res.updateRow(); // Päivittää lähderelaation vastinrivin 4-3-OhjRajapinnat Teuhola 2012

133 Esimerkki ResultSet-päivityksestä
// Relaatio: Tuote(Tno, Tnimi, Valmistaja, Hinta) // Laske ‘Vipu Oy:n’ tuotteiden hintoja 5 €:lla. // public static void laskeHintoja(Connection conn) throws Exception { String kys = "SELECT * FROM Tuote WHERE Valmistaja='Vipu Oy‘;"; Statement lause = conn.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet res = lause.executeQuery(kys); while (res.next()) { res.updateInt("hinta", res.getInt("hinta") - 5); res.updateRow(); } res.close(); conn.commit(); conn.close(); 4-3-OhjRajapinnat Teuhola 2012

134 Ehtoja ResultSet-päivitykselle
Tulosrivien alkuperä tietokannassa pitää pystyä automaattisesti ja yksikäsitteisesti selvittämään Päivitys mahdollinen, jos Tulosjoukko on peräisin yhdestä relaatiosta (ei esim. liitoksia) Relaation pääavain on mukana tulosattribuuteissa. Huom! Kyseessä on täsmälleen sama ongelma kuin näkymän (view) päivityksessä. Resultset on itse asiassa eräs näkymä kantaan 4-3-OhjRajapinnat Teuhola 2012

135 JDBC: Mielivaltaiset lauseet
Jos lauseesta ei etukäteen tiedetä, onko se kysely vai päivitys (esim. käyttäjä on syöttänyt sen suorituksen aikana), käytetään execute()-metodia, joka palauttaa boolean-arvon true, jos lause oli kysely, muuten false. Tuloksen poiminta tehdään eri tavoilla tästä riippuen. 4-3-OhjRajapinnat Teuhola 2012

136 Esimerkki: SQL-lauseen lukeminen näppäimistöltä ja suoritus
… String lause = prompt(“Anna SQL-lause”); Statement st = conn.createStatement(); boolean tulos = st.execute(lause); if (tulos) { ResultSet rs = st.getResultSet(); … } else { int lkm = st.getUpdateCount(); … } … 4-3-OhjRajapinnat Teuhola 2012

137 Kyselyn tulokseen liittyvä metadata
Tarvitaan, jos metadata (eli skeemaan liittyvä data) ei ole tiedossa ohjelmaa kirjoitettaessa (vrt. ed. sivun esimerkki). … ResultSet rs = st.getResultSet(); ResultSetMetaData rsmd = rs.getMetaData(); int sarLkm = rsmd.getColumnCount(); for (int sar = 1; sar <= sarLkm; sar++) { System.out.println(“Sarake no “ + sar); System.out.println(“Nimi: “+ rsmd.getColumnName(sar)); System.out.println(“Tyyppi: “ rsmd.getColumnTypeName(sar)); … } 4-3-OhjRajapinnat Teuhola 2012

138 Tietokantayhteyteen liittyvä metadata
Toistasataa erilaista tietoa, esim. tiedot ajurista: … Connection conn = DriverManager.getConnection(…); DatabaseMetaData dbmd = conn.getMetaData(); System.out.println(“Ajuri: “ + dbmd.getDriverName()); System.out.println(“Versio: “ + dbmd.getDriverVersion()); … 4-3-OhjRajapinnat Teuhola 2012

139 Transaktioiden hallinta
Oletusarvoisesti jokainen lause muodostaa oman transaktionsa. Eksplisiittinen hallinta (conn tyyppiä Connection): conn.setAutoCommit(false); … …Päivityslauseita … conn.commit(); // tai conn.rollback(); Voi syntyä SQLException, joka on käsiteltävä. 4-3-OhjRajapinnat Teuhola 2012

140 Ohjelmointitekniikoista
Java-ohjelmoinnissa luokkien suunnittelu on keskeisessä asemassa. Tietokannan käyttö kannattaa keskittää omiin luokkiinsa/metodeihinsa, esim. seuraavasti: Ajuriin liittyvät toiminnot Tietokantayhteyteen liittyvät toiminnot Relaatioita edustavat ‘kuoriluokat’ (‘wrapper’) Relaatioiden rivejä (= tietokannan varsinaisia ‘olioita’) edustavat luokat Varsinaiset sovellukset 4-3-OhjRajapinnat Teuhola 2012

141 Esimerkki apuluokasta: Ajurin ja tietokantayhteyden hallinta
import java.io.*; import java.sql.*; import java.util.*; public class Yhteys { public static Connection luoYhteys(String kanta) throws Exception { String driver = "org.postgresql.Driver"; String url = "jdbc:postgresql://kanta.cs.utu.fi:5432/" + kanta; String user = “ewert"; BufferedReader in = new BufferedReader(new FileReader("sala.txt")); String pwd = in.readLine(); Class.forName(driver); Connection conn = DriverManager.getConnection(url, user, pwd); return conn; } public static void suljeYhteys(Connection conn) throws Exception { conn.close(); } 4-3-OhjRajapinnat Teuhola 2012

142 Esimerkki relaation riviä edustavasta luokasta
// Asiakas-entiteetti import java.util.*; public class Asiakas { private int ano; // Yksityiset private String animi; // esiintymä- private String paikka; // muuttujat public Asiakas(int no, int ni, String pa) { Ano = no; animi = ni; paikka = pa; // Alustaja } public int getAno() { return ano; } // Ns. public String getAnimi() { return animi; } // getter- public String getPaikka() { return paikka; } // metodit public String toString() { return getAno()+”, ’”+getAnimi()+’”, ”’+getPaikka()+”’”; } 4-3-OhjRajapinnat Teuhola 2012

143 Esimerkki relaation ‘kuoriluokasta’
// Asiakas(Ano, Animi, Paikka)-relaatiota edustava luokka import java.util.*; import java.sql.*; public class Asiakkaat { // Uuden asiakkaan lisäys; yhteys oltava luotu public static void uusiAsiakas(Connection conn, Asiakas a) { try { Statement st = conn.createStatement(); String lause = "INSERT INTO Asiakas VALUES(" + a.toString() + “)”; int riveja = st.executeUpdate(lause); conn.commit(); } catch (SQLException se) { System.out.println("Lisäys pieleen!“ + se.toString()); } } 4-3-OhjRajapinnat Teuhola 2012

144 Esimerkki relaation ‘kuoriluokasta’ (jatk.)
// Paikkakunnan asiakkaiden haku Asiakas-relaatiosta (vrt. aik. esim.) // public static ArrayList<Asiakas> haeAs(Connection conn, String pnimi) { ArrayList<Asiakas> arr = new ArrayList<Asiakas>(); try { Statement st = conn.createStatement(); String lause = “SELECT Ano, Animi, Paikka “ + “FROM Asiakas WHERE Paikka =‘”+pnimi + “‘;”; ResultSet res = st.executeQuery(lause); while (res.next()) { Asiakas a = new Asiakas( res.getInt(“Ano”), res.getString(“Animi”), res.getString(“Paikka”)) arr.add(a); } res.close(); } catch (SQLException se) { System.out.println("Paikanhaku ei onnistunut!“ + se.toString()); } return arr; 4-3-OhjRajapinnat Teuhola 2012

145 Esimerkki relaation ‘kuoriluokasta’ (jatk.)
// Asiakkaan paikkakunnan muutos public static void muutaPaikka( Connection conn, Asiakas a, String uusiPaikka) { try { conn.setAutoCommit(false); // Transaktio hallitaan itse Statement st = conn.createStatement(); String lause = “UPDATE Asiakas “ “SET Paikka=‘” + uusiPaikka + “‘” “WHERE Ano=" + a.getAno() + “;”; int riveja = st.executeUpdate(lause); conn.commit(); // Muutoksen vahvistus } catch (SQLException se) { System.out.println("Paikanmuutos epäonnistui:“+se.toString()); try { conn.rollback(); } catch (SQLException re) { // Peruutus System.out.println(“Rollback meni pieleen: “+ re.toString()); } } } 4-3-OhjRajapinnat Teuhola 2012

146 Esimerkki relaation ‘kuoriluokasta’ (jatk.)
// Koko asiakastaulun tulostus ruudulle public static void tulostaKaikki(Connection conn) { try { Statement st = conn.createStatement(); String lause = "SELECT * FROM Asiakas;"; ResultSet res = st.executeQuery(lause); System.out.println(""); System.out.println(" Ano | Animi | Paikka"); System.out.println(" "); while (res.next()) { System.out.print(res.getInt(1)); System.out.print(" | "); System.out.print(res.getString(2)); System.out.print(" | "); System.out.println(res.getString(3)); } res.close(); } catch (SQLException se) { System.out.println( "Asiakkaiden haku ei onnistunut!“ + se.toString()); 4-3-OhjRajapinnat Teuhola 2012

147 Esimerkki kuoriluokan testiohjelmasta
public static void main( String args[ ] ) throws Exception { Connection conn = Yhteys.luoYhteys("til"); // Alustus Asiakkaat.tulostaKaikki(conn); // Rel. sisältö alussa Asiakas a = new Asiakas(444, "Laine", "Naantali”); Asiakkaat.uusiAsiakas(conn, a); // Uuden lisäys Asiakkaat.tulostaKaikki(conn); // Uusi sisältö ArrayList<Asiakas> arr = Asiakkaat.haePaikka(conn, "Turku"); // Kysely System.out.println("Turkulaiset asiakkaat: "); // Vastaus for (int i=0; i<arr.size(); i++) { System.out.println(arr.get(i).toString()); } // Turkulaiset Asiakkaat.muutaPaikka(conn, a, "Raisio"); // Paikkakunnan vaihto Asiakkaat.tulostaKaikki(conn); // Muutettu sisältö Yhteys.suljeYhteys(conn); // Lopetus } 4-3-OhjRajapinnat Teuhola 2012

148 Tietokantasovelluksen laatimisesta
Voidaan käyttää erilaisia ohjelmistoratkaisuja, eli ns. suunnittelumalleja. Yleinen periaate: tietokantaa käsittelevien toimintojen eristäminen omiin luokkiinsa, jolloin niiden ylläpito selkeytyy. Esim. Data Access Objects (DAO) –malli: Kerrosmainen arkkitehtuuri: Käyttöliittymä Sovelluslogiikka Tietokantaa käsittelevät osat sovelluksesta JDBC-rajapinta Tietokanta 4-3-OhjRajapinnat Teuhola 2012

149 Tietokantaa käsittelevien luokkien rakenteellisia vaihtoehtoja
Muodostetaan yksi (iso) luokka, johon kerätään kaikki tietokantaa käsittelevät metodit. Muodostetaan yksi luokka kutakin tietokannan entiteettikokoelmaa (eli relaatiota) kohti, johon kootaan ko. relaatioon liittyvät metodit, mutta mahdollisesti myös esim. liitosoperaatiot muiden relaatioiden kanssa. Muodostetaan yksi luokka kutakin entiteettityyppiä kohti, jonka instanssit vastaavat relaation yksittäisiä rivejä. Yllä tilaus-asiakas-sovelluksessa käytettiin lähinnä kakkosvaihtoehtoa (luokka ’Asiakkaat’). Harjoitustyön malliesimerkissä on piirteitä 1- ja 3-vaihtoehdoista. 4-3-OhjRajapinnat Teuhola 2012

150 Object-relational mapping (ORM)
Relaatiokannan sovellusohjelmointi sisältää runsaasti saman kaavan mukaisia metodeja, jotka muuntavat Javan olioesityksen relaatiomallin mukaiseksi taulukkoesitykseksi ja päinvastoin. Muunnos on mahdollista osittain automatisoida, mikä nopeuttaa sovelluskehitystä ja ylläpitoa. Tarvitaan muunnoksen kuvaus loogisella tasolla. Tämä tehdään usein erillisenä kuvaustiedostona (tyypillisesti XML-kielellä). Ei poista tietokannan suunnittelutarvetta. Esimerkki ORM-tuotteesta: Hibernate 4-3-OhjRajapinnat Teuhola 2012


Lataa ppt ""

Samankaltaiset esitykset


Iklan oleh Google