1
Bevezetés
1.1 Általános bevezetés 1.2 A könyv használatáról Hová és hogyan telepítsük majd a szoftvereket?
Gyakran fogunk más által készített szoftvert (adatbázis-kezelőt, fejlesztőeszközt, egyebet) használni, többnyire Javában írottakat (s azokat szinte mindig archív állományból). Sokkal egyszerűbb lesz velük a munka, ha nem ötletszerűen telepítjük őket, hanem külön-külön könyvtárakban ugyan, de egyazon könyvtár alá; ez a közös „őskönyvtár” windowsos rendszerekben a c:\Program Files lehet, linuxos rendszerekben például a /opt könyvtár. A telepítendő szoftvereket általában ZIP-állományban tölthetjük le az internetről; telepíteni a jar programmal telepíthetjük őket. Lépjünk át a c:\Program Files könyvtárba (Linuxon a /opt könyvtárba), és – ha például a McKoi adatbázis-kezelőt akarjuk majd telepíteni – parancssorból adjuk ki a következő parancsot: jar xvf c:\Downloaded\McKoi\mckoi1.0.3.zip
(ha az internetről letölthető mckoi1.0.3.zip állományt a c:\Downloaded\McKoi könyvtárba mentettük); erre a parancsra a Program Files könyvtárban megjelenik majd egy mckoi1.0.3 nevű alkönyvtár, és ezzel túl is jutunk majd a telepítésen. Programfuttatás
Jól emlékszünk még a javás programok parancssorból való futtatására (lásd Angster Erzsébet: Objektumorientált tervezés és programozás 2, 1. fejezet, 1.4. szakasz); már a következő fejezetben be kell majd írnunk a parancssorba a következőket: java -classpath "c:\Program░ Files\Java\j2sdk1.4.2_06\demo\jfc\TableExample\TableExample.jar";"c:\Progra m Files\hsqldb\lib\hsqldb.jar"; TableExample
(ez egyetlen sor; a ░ karakter szóközt jelöl). A java (a Java virtuális gépet elindító alkalmazás) elé sohasem írok majd útvonalat (felteszem, hogy az Olvasó operációs rendszere „ismeri” a helyét). Ezt a sok mindent beírni a parancssorba – „összevadászni” az erőforrásokat, észben tartani, hogy melyik osztály main metódusát kell elindítani – nem mindig egyszerű feladat. Megtehetjük, hogy mindent rögtön parancsállományba (Linuxban: héjszkriptbe) írunk, de van más lehetőségünk is: projektet használni. Programfuttatás projektből Mivel nem tudni, hogy az Olvasó milyen fejlesztőeszközt használ majd, azért csak vázlatosan írhatom le a teendőket. Ha az iménti TableExample osztály main metódusát szeretnénk projektből elindítani, akkor előbb hozzunk létre egy projektet (projektállományt), az erőforrásai közé írjuk be a TableExample.jar állományt (persze az útvonalával együtt), meg a hsqldb.jar állományt (szintén útvonalastul); ezzel megvan a két erőforrás. Futtatandó osztályként írjuk be a TableExample osztályt (pontosabban szólva, azt kell megértetnünk a fejlesztőeszközzel, hogy ennek az osztálynak a main metódusát akarjuk futtatni). Ebben a példában a TableExample.main metódusnak nem adunk át parancssori paramétereket; a 1. oldal
fejlesztőeszközök nagy részével azonban ezt is megtehetnénk, ha kellene. Ezzel a módszerrel magából a fejlesztőeszközből indíthatjuk a programokat, nem kell „kifurakodnunk” a parancssorig, de ennek a kényelemnek ára van: a fejlesztőeszközre voltaképpen nincs szükség, az csak a mi kényelmünk kedvéért köti le a számítógép erőforrásait (egy kamiont is lehet gázolaj tartására használni, mert jó nagy az üzemanyagtartálya). Persze ha a gép nagy teljesítményű, akkor ez a fölös teher nem lesz olyan vészes. Kivételkezelés
Az adatforrásokkal való munkában lépten-nyomon kell kivételt kezelni, s ez természetes is, mert bármikor megszakadhat a kapcsolat az adatforrás kezelőjével, hibás lehet az átküldött SQL-utasítás, az SQL-utasításba beírt tábla esetleg nem is létezik stb. A könyvben azonban a lényeget szerettem volna világosan megmutatni, s emiatt gyakran úgy intéztem el a kivételeket, hogy a main metódus révén (throws Exception) mindegyiket áthárítottam a Java virtuális gépre – kezelje őket az. Ez nem éppen felhasználóbarát módszer (és nem is piacképes). Tényleges, végfelhasználóknak írandó programban az ilyesmi megengedhetetlen; az Olvasó tehát szakdolgozatban és másutt ne kövesse példámat, hanem legfőképpen a végfelhasználó felkészültségét és igényeit tartsa szem előtt. Forráskódmelléklet
A kötetben szinte mindenütt megadtam a teljes forráskódot, de talán gyorsabb és egyszerűbb a munka, ha külön állományban is megvannak; lásd a mellékelt ZIP-állományt.
2. oldal
2
Ismerkedés a JDBC API-val
2.1 Adatok – honnan és hová? A Javában írt programokban vannak adatok is – rendszerint objektumok adattagjaiba foglalva, de csak rendszerint, nem mindig. Honnan valók ezek az adatok? Némelyik – ha primitív vagy String típusú – mint literál már eleve bele van foglalva a forráskódba, mondjuk, a gravitációs állandó vagy a Planck-féle állandó egy fizikai számítás kódjába vagy a pi szám egy geometriai vonatkozású programéba. Minden más adat kívülről származik, a legkülönfélébb helyekről: az operációs rendszertől (az operációs rendszert kérdeztetjük meg a programmal, ha, mondjuk, a képernyőfelbontásra vagy valamelyik környezeti változó értékére vagyunk kíváncsiak) vagy az állományrendszer valamelyik állományától (például konfigurációs állománytól); a (hús-vér) felhasználótól (a felhasználó mindjárt a program indításakor megadhat adatokat – gondoljunk a main metódus parancssori paramétereire –, vagy később, ha például felhasználóazonosítót és jelszót ír be); más rendszertől, például egy, az operációs rendszer futtatta másik programtól (esetleg éppen egy vírustól), egy távoli számítógépen futó programtól vagy talán egy mérőberendezéstől: szélerősség- vagy hőmérsékletmérőtől, netán földrengésjelző készüléktől. Az adatok persze nem csak eredetük szerint különböznek egymástól, hanem „szervezettségükben” is: a seti@home program egy nagy állományba foglalt adatokkal dolgozik, és azt igyekszik kideríteni, hogy mi kapcsolja egybe az időben egymás utáni adatokat (a rádiótávcsövek által észlelt elektromágneses sugárzás különféle időpontokban mért erősségét); egy kereskedelmi adatbányászati program például annak a kiderítésére szolgálhat, hogy azok a vásárlók, akik sört vesznek egy üzletlánc üzleteiben, mekkora hányadban vesznek egyszersmind trappista sajtot is (mert akkor érdemes a kettőt egymás közelébe tenni); egy vállalatirányítási rendszernek egyebek között az lehet a feladata, hogy figyelje a raktárkészletet, és ha annak a nagysága egy előre meghatározott szint alá esik, akkor utánpótlást kérjen a beszállító partnerektől. a beléptetőprogramok felhasználóazonosítót és jelszót tartanak nyilván (esetleg ujjnyomot vagy íriszképet), meg a felhasználónak adott jogokat: a különféle állományokhoz és könyvtárakhoz, erőforrásokhoz stb. való hozzáférés jogát és egyebeket – például azt, hogy melyik szobába mehetnek be. Ezekből a példákból az derülhet ki, hogy némely esetben már ismerjük a dolgok rendjét, az „ügymenetet”, a folyamatokat (például egy vállalat működésében) vagy éppen most alakítjuk ki őket (vállalatirányítási rendszerek bevezetésekor gyakran ez a helyzet: az addigiaknál átláthatóbb folyamatokat kell bevezetni). Más helyzetekben meg nem ismerjük a dolgok, adatok közötti összefüggést; éppen az a feladat, hogy kiderítsük, vajon vannak-e közöttük valamiféle összefüggések. A seti@home program olyan periodikus jelenségeket igyekszik feltárni, amelyek nem magyarázhatók meg már ismert csillagászati tényekkel (forgó csillag elektromágneses sugárzásnyalábjával és egyebekkel), hanem valamilyen nem földi civilizáció jelenlétére utalhatnak. Ezekhez a feladatokhoz természetük szerint más-más fajtájú adatforrás illik: a seti@home programhoz egyszerű adatállomány: valós számok egymás után (azok írják le az elektromágneses sugárzás erősségét az szabályos időközönként egymásra következő pillanatokban); a vállalatirányítási rendszer nyilván valamiféle (alighanem relációs) adatbázis-kezelő rendszertől szerzi majd meg a működéséhez szükséges adatokat (egyebek között azért, mert az adatokon meg kell osztoznia más rendszerekkel, s mert ezeket az adatokat védeni kell a kíváncsiskodóktól, 3. oldal
ezenfelül koordinálni kell a különféle rendszerek munkáját, ha azok egyszerre akarnák ugyanazt az adatot olvasni, megváltoztatni vagy törölni); a beléptetőprogram esetleg szintén adatbázis-kezelőt használ, de nem relációst, hanem hierarchikust, használhat azonban állományba mentett objektumokat is (szerializált – „bájtsorba fejtett” objektumokat). Röviden és magyarán az adatokat nem kell (és lehet) mindig adatbázisból venni. Gondoljunk arra, hogy az adatbázisok kialakításakor egyedekből és azok különféle tulajdonságaiból és kapcsolataiból indulunk ki, és nincs semmi kétségünk az egyedek létezése felől, sőt van róluk valamiféle adatmodellünk. Másfelől viszont gondoljunk egy tünetegyüttesre (szindrómára), mondjuk, egy beteg ember tüneteinek együttesére. Elsőre esetleg egyáltalán nem nyilvánvaló, hogy a tünetek egymással összefüggő együttest alkotnak, az meg kivált nem, hogy esetleg kétféle tünetegyüttesről van szó (pedig megtörténhet, hogy a beteg ember kétféle kórban szenved), az még végképp nem, hogy ezek voltaképpen nem egyszerűen a beteg ember tünetegyüttesei, hanem betegségeké! Más szóval ismerjük a tulajdonságokat, de talán még nem sejtjük, hogy azok nem egy emberegyed, hanem egy (vagy több) betegségegyed tulajdonságainak veendők; az csak később, orvosi tapasztalatok és kutatások révén derül majd ki. A következőkben olyanfajta „adat-összetartozással” foglalkozunk majd, amely táblázatban is megjeleníthető – olyasféle táblázatról vagy táblázatokról lesz szó, amilyeneket a táblázatkezelő programok és a (például relációs) adatbázisok használnak. A Java nyelv az ilyen – táblázatba foglalt – adatok programba való bevitelére (és programból való kivitelére) egyebek – például az SQLJ, a JDO (Java Data Objects) mellett – a JDBC API-t kínálja. 2.2 Mi a JDBC API? Kezdjük a könnyebbik végén: mi az API? Az API mozaikszó az Application Programming Interface szóösszetétel kezdőbetűiből; magyarul apinak ejtik (némelyek azonban éjpiájnak) és alkalmazásprogramozási felületnek mondják (más fordítás szerint eljáráshívási felületnek). A javabeli API-k mind osztályokból és interfészekből álló csomagok – a JDBC API például két csomag, a java.sql és a javax.sql osztályaiból és interfészeiből épül fel. Mire jó egy ilyen API? Arra, hogy a felhasználónak (itt éppen a programfejlesztőnek) csak a felszínt kelljen ismernie, a felület mögötti mélységeket már ne. Ezt a helyzetet mindenkinek ismerős, aki foglalkozott Javával, hiszen az egész J2SE (vagyis a Java 2 platform standard kiadása) is csak egy jókora API: elég ismernünk a Java csomagok osztályait és interfészeit, de azt már nem, hogy a mélyben az osztályok hogyan kapcsolódnak – a Java virtuális gép közvetítésével – az operációs rendszerhez. A Java 2 API hajítófát sem érne Java virtuális gép és operációs rendszer nélkül (hacsak a Sun vagy más nem készítene olyan processzort, amely közvetlenül értelmezné a bájtkódot). Az API (pontosabban: a megtestesült API) tehát átlátható felület kínál belső folyamatok működtetésére. Egyelőre ennyi elég is lesz az API-ról; térjünk most át a JDBC-re. A JDBC szó az ODBC (Open Database Connection) mintájára készült, s a köztudomás szerint a Java Database Connection szóegyüttes rövidítése. A JDBC API pedig egy megtestesítésre váró váz: a felületén osztályokat és interfészeket (adattagokat és metódusokat) kínál, s ha implementálják, akkor belül osztályokat állít az interfészek mögé és rajtuk keresztül összekapcsolódik valamilyen adatforrás adatcsere-felületével. A megtestesített JDBC API legfőképpen két dologra való: arra, hogy az alkalmazói programok fejlesztői JDBC API-beli osztályokra és megtestesített interfészekre támaszkodva kapcsolatba léphessenek adatforrásokkal; és arra, hogy ha már megvan a kapcsolat az adatforrással, akkor a fejlesztő – megint csak JDBC API-beli osztályok és implementált interfészek metódusainak közvetítésével – az adatforrás 4. oldal
„természetes” nyelvén (az esetek többségében SQL nyelven) definiálhassa, manipulálhassa és felügyelhesse az adatokat – és a Java által feldolgozható alakban választ kapjon a kérdéseire (például lekérdezésekre). A JDBC API egy osztály- és interfészegyüttes. Ha tényleges adatforrásokkal akarjuk használni, akkor interfészeit implementálni kell. A JDBC API arra szolgál, hogy az osztályai révén a Javában írt programok a táblázatos adatforrások kezelőinek saját nyelvét használhassák (rendszerint az SQL nyelvet) táblázatba foglalt adatok kezelésére (lekérdezésére, megváltoztatására, törlésére, felügyeletére stb.) Mindehhez talán elkél egy kis magyarázat: A JDBC API – mint már leszögeztük – a J2SE API része, és „használat előtt implementálandó”: ahhoz, hogy a közvetítésével adatokat lehessen lekérdezni, mondjuk, egy Oracle adatbázisból, előbb implementálni kell – hozzáidomítani az Oracle adatbázis-kezelőjéhez. Ha meg egy Sybase adatbázissal kell adatokat cserélni, akkor a Sybase adatbázis-kezelőjéhez való implementációra van szükség – ahányféle adatforrás, annyiféle JDBC API-implementáció. Az implementálás munkáját vagy az adatbázis-kezelő gyártója végzi el, vagy valaki más; az alkalmazói program fejlesztője az implementációt már készen kapja (fizetős vagy valamilyen más licenccel). Az implementáció birtokában az alkalmazói szoftver fejlesztője mindig ugyanazokat a metódusokat használhatja az adatforrással való kapcsolat kiépítésére – ha Excel-munkafüzet az az adatforrás, ha DB2 adatbázis. Ha már megvan a kapcsolat, akkor az adatcsere az adatforrás nyelvén zajlik: az adatforrást kezelő szoftverhez az implementált JDBC API metódusai révén juttathatók el az adatdefiníciós, adatkezelő és adatfelügyeleti utasítások (mint paraméterek írandók be a metódusokba). A JDBC API tehát csak közvetíti ezeket a (rendszerint SQL nyelvű) utasításokat; az értelmezés már az adatforrást kezelő szoftver dolga. A JDBC API azonban másra is jó; például annak a kiderítésére, hogy hány oszlopos táblázat jön majd válaszul erre vagy arra a lekérdezésre, vagy annak a kiderítésére, hogy van-e egy adatbázis valamelyik táblájában elsődleges kulcs és ha van, akkor melyik oszlop az (vagy melyik oszlopok azok). A JDBC API révén nemcsak közönséges adatokhoz lehet hozzáférni, hanem adatokat leíró adatokhoz – más szóval metaadatokhoz – is. A JDBC API a táblázatba foglalt adatok mellett hozzáférhetővé tesz bizonyos, az adatforrásra vonatkozó adatokat (metaadatokat) is. 2.3 Egy példa Feladat – Adatok táblázatos megjelenítése Jelenítsünk meg táblázatban egy szöveges állományba foglalt táblázatot! Első példaképpen megnyitunk egy adatforrást – egy szöveges állományba foglalt táblázatot, nevezetesen a Orsz_irszam_orszagos.csv állományt. Ebből a táblázatból egyebek között az olvasható ki, hogy Magyarországon a postai irányítószámok mely helységnevekkel tartoznak össze (Budapestet, Debrecent, Győrt, Miskolcot, Pécset és Szegedet leszámítva). Az állomány maga az Orsz_irszam_orszagos.XLS nevű, a www.posta.hu webhelyről letölthető Excel-állományból készült, és az egy sorba tartozó mezőket tabulátorkarakterek (ASCII 9) választják el benne.
5. oldal
A JDBC API felülete
Határfelület a JDBC API implementációja és az adatforrás kezelője között
A JDBC API-ra támaszkodó program
Határfelület az adatforrás kezelője és az adatforrás között
Az adatforrás Az adatforrást kezelő program
A JDBC API implementációja 1. ábra. Egy JDBC API-ra támaszkodó program összekapcsolódása egy adatforrással A JDBC API-val kapcsolatban említett négy összetevőből: a megfelelően implementált JDBC API-ra támaszkodó alkalmazásból, a JDBC API megfelelő implementációjából, az adatforrást kezelő szoftverből (ezzel kell a JDBC API implementációjának „szót értenie”), és az adatforrásból megvolna tehát az egyik: az adatforrás. Az adatforrás-kezelő és a hozzá való JDBC API-implementáció
Az Orsz_irszam_orszagos.csv nevű adatforrás kezelésére a HSQLDB nevű adatbázis-kezelőt fogjuk használni; ez Javában írt, szabad forráskódú, a GNU nyilvános licencében (a GPL-ben) leírt módon használható szoftver, és szöveges állományokba foglalt táblázatokat is kezel (a http://hsqldb.sourceforge.net webhelyen megadott további webhelyekről tölthető le ZIPállományként). A ZIP-állomány (2005 áprilisában ez a hsqldb_1_7_3_3.zip nevű állomány) egy hsqldb nevű könyvtárat foglal magába. Ezt a ZIP-állományt az 1. fejezet 1.2. pontjában leírt módon fogjuk kicsomagolni, vagyis átlépünk a C:\Program Files könyvtárba (Linuxban az /opt könyvtárba), és kiadjuk a 6. oldal
jar xvf C:\Downloaded\hsqldb\hsqldb_1_7_3_3.zip
parancsot (feltéve, hogy a hsqldb_1_7_3_3.zip állomány a letöltéssel a C:\Downloaded\hsqldb könyvtárba került – ha máshová, akkor más útvonalat kell beírni; s ha a jar program nem látható a C:\Program Files könyvtárból, akkor eléje kell írni az útvonalát is). És most elindítjuk a Orsz_irszam_orszagos.csv adatforrás kezelőjét, a Hsqldb Server nevű kiszolgálót; ehhez a hsqldb\lib\hsqldb.jar archív állomány org.hsqldb.Server nevű osztályát kell működésbe léptetni, a következő parancssori paraméterekkel: java -classpath C:\Program Files\hsqldb\lib\hsqldb.jar; org.hsqldb.Server░ -database.0 mydb -dbname.0 xdb
(mindezt persze sortörés nélkül kell a parancssorba írni). Felbukkan egy konzol, és megjelenik rajta néhány sor; az utolsó öt valami efféle: [Server@f9f9d8]: Database [index=0, id=0, db=file:mydb, alias=xdb] opened sucessfully in 1820 ms. [Server@f9f9d8]: Startup sequence completed in 4950 ms. [Server@f9f9d8]: 2005-03-27 15:37:11.51 HSQLDB server 1.7.3 is online [Server@f9f9d8]: To close normally, connect and execute SHUTDOWN SQL [Server@f9f9d8]: From command line, use [Ctrl]+[C] to abort abruptly
Működik tehát az adatforrást kezelő szoftver: a Hsqldb Server. A konzolablakot végig ne zárjuk be, mert azzal megszakítjuk ennek a kiszolgálónak a futását. A figyelmes olvasó észreveheti, hogy abban a könyvtárban, ahol a Java virtuális gép elindult, három új állomány jelenik meg: a mydb.log, a mydb.lck és a mydb.properties (a mydb név ismerős lehet a kiszolgálót elindító parancsból). Az alkalmazói szoftver
A JDBC API-ra támaszkodó alkalmazói szoftver a JDK egyik demonstrációs célú szoftvere lesz; nem tesz semmi különöset az adatokkal, nem változtat rajtuk semmit, ő van az adatokért, s nem azok őérte: egyes-egyedül arra való, hogy megjelenítse őket – és ebben a minőségében még nagy hasznunkra lesz. A felhasználó szabja meg – SELECT utasítások kiadásával – hogy a megjelenítésre használt javax.swing.JTable típusú objektumban milyen adatok tűnjenek fel. Ez a szoftver a JDK könyvtárának demo nevű alkönyvtárában van meg mint a demo\jfc\TableExample\TableExample.jar archív állomány TableExample nevű osztálya. Ennek az osztálynak a main metódusát most egy másik Java virtuális gépen indítjuk el (Linuxban a két JAR-állomány közé kettőspontot kell írni, nem pontosvesszőt): java -classpath "c:\Program░ Files\Java\j2sdk1.4.2_06\demo\jfc\TableExample\TableExample.jar";"c:\Progra m Files\hsqldb\lib\hsqldb.jar"; TableExample
a szürke háttérrel megjelölt archív állomány kapcsolja majd össze ezt az alkalmazói szoftvert az adatforrás kezelőjével: ez tehát a JDBC API ide illő implementációja! (Elsőre talán gyanús vagy legalábbis furcsa, hogy ez ugyanaz az archív állomány, amely a kiszolgáló elindításához kellett; holott csak arról van szó, hogy a HSQLDB fejlesztői ugyanabba az archív állományba tették a kiszolgáló futásához szükséges csomagokat meg a JDBC API-t implementáló csomagokat; ha az Olvasó különösen hitetlen, akkor válassza szét ezt a két csomagrendszert két külön archív állományba, és őket használja a hsqldb.jar helyett; így meggyőződhet róla, hogy semmi turpisság nincs a dologban.) Egy dialógusablak fog feltűnni: 7. oldal
A szövegmezők tartalmát átírjuk: a User name: feliratú címke melletti szövegmezőbe azt írjuk be, hogy sa; és a Password: utáni szövegmező tartalmát töröljük; a Database URL: feliratú címke mellé azt írjuk be, hogy jdbc:hsqldb:hsql://localhost/xdb; a Driver: felirat mellé meg azt, hogy org.hsqldb.jdbcDriver (hogy miért éppen ezeket kell beírni, arról hamarosan lesz szó, de előbb lássuk végre, hogy működik a dolog!). A dialógusablak tehát így fog festeni:
Ha tényleg ez látszik rajta, akkor nyomjuk meg a Connect gombot. Egy keret (javax.swing.JFrame osztályú objektum) fog megjelenni:
Fut már tehát a kiszolgáló (az adatforrás kezelésére kiszemelt szoftver), egy másik Java virtuális gépen meg egy alkalmazás; s ez a másik virtuális gép „látja” a JDBC API-t implementáló csomagok 8. oldal
osztályait is. Csak az adatforrás „nincs még játékban”. Bekapcsoljuk az adatforrást
A TableExample feliratú keret szerkeszthető szövegterületére beírjuk a következő SQL-utasítást: CREATE TEXT TABLE Irszam ( IRSZ Varchar, ST Varchar, MB Varchar, V Varchar, T_P Varchar, Ph Varchar, Cp Varchar, Kko Varchar, Fbl Varchar, Fbm Varchar, Kb Varchar, NemTudniMi Varchar, M Varchar, Telepules_neve Varchar, Posta_neve Varchar );
ha megnyomjuk a Fetch feliratú gombot, akkor létrejön egy HSQLBD-beli (adatbázis)tábla; ezt a táblát fogjuk nyomban összekapcsolni az Orsz_irszam_orszagos.csv nevű táblázatos állománnyal (a CSV annyit jelent, hogy Comma Separated Values, azaz egymástól vesszővel elválasztott adatok; a vessző helyett állhat az értékek között más karakter is, mi most éppen a tabulátorkaraktert használjuk). Másoljuk be az Orsz_irszam_orszagos.csv nevű állományt abba a könyvtárba, ahol a kiszolgálót elindítottuk; az odakerül tehát a mydb.log, a mydb.lck és a mydb.properties mellé. Térjünk vissza a TableExample feliratú kerethez, töröljük le a szövegterületről az előző SQLutasítást, és írjuk a helyébe ezt: SET TABLE Irszam░ SOURCE "Orsz_irszam_orszagos.csv;encoding=Cp1250;ignore_first=true;fs=\t";
ezzel összekapcsolódik az előbbi Irszam nevű adatbázistábla és az adatforrás (a további paraméterek arra valók, hogy a Hsqldb Server megjelenítse az ékezetes magyar karaktereket, hagyja figyelmen kívül az adatforrás első sorát és a tabulátorkaraktert vegye az értékek közötti elválasztó karakternek). Megint nyomjuk meg a Fetch gombot. (A konzolon látszik, hogy a TableExample valamelyik metódusa mindkétszer kivételt ejt, mert nem SELECT utasítást adtunk ki, de ez ne zavarjon bennünket.) És most írjuk be a SELECT * FROM Irszam;
SQL-utasítást (a Fetch gombot is nyomjuk meg!); ha minden a helyén volt, akkor ezt látjuk:
9. oldal
Megjelentek tehát az adatforrás adatai! Ha kigyönyörködtük magunkat, akkor írjuk be a keret szövegterületére a SHUTDOWN utasítást – ez leállítja majd a HSQLDB kiszolgáló futását –, és lépjünk ki a TableExample alkalmazásból is. Megjegyzések Adatbázistáblákhoz szokott szemnek nem éppen üdítő látvány ez a táblázat, mert az üres mező itt sokszor nem azt jelenti, amit az adatbázistáblákban a null (hogy ugyanis a tulajdonságnak nem ismeretes az értéke vagy értelmetlenség is lenne az értékéről beszélni), hanem vagy azt, hogy false, vagy azt, hogy az itteni érték ugyanaz, mint az utolsó nem üres mezőben volt (például Érd alatt 5 üres mező van egymás után; ez annyit jelent, hogy a hozzájuk tartozó 5 irányítószám is érdi, csak más-más postahivatalhoz tartozik). Egyet-mást azonban még ebből a „lyukas” táblából is ki lehet deríteni; például azt, hogy van olyan irányítószám, amelyhez több helységnév tartozik. Írjuk csak be a szövegterületre azt a (kissé hosszú) SQL-utasítást, hogy SELECT IRSZ, COUNT(IRSZ) FROM Irszam GROUP BY IRSZ HAVING COUNT(IRSZ) > 1░ ORDER BY 2 DESC;
és nyomban kiderül, hogy például a 7838-as irányítószámmal nyolc Baranya megyei helységnév van összekapcsolva; a SELECT Telepules_neve FROM Irszam WHERE IRSZ = '7838';
SQL-utasítás mindjárt meg is mutatja, hogy ez a nyolc Besence, Hirics, Lúzsok, Nagycsány, Páprád, Piskó, Vajszló és Vejti. Egy újabb SQL-utasítás révén azt is megtudhatjuk, hogy összesen 342 irányítószámhoz tartozik legalább két helységnév, vagyis ez a „jelenség” egyáltalán nem ritka. Ha valaki nem szeretne ennyit bajlódni az alkalmazói program elindításával, inkább rögtön az eredményt látná (és evégett hajlandó lemondani az „interaktivitásról”), akkor ne a TableExample osztály main metódusát indítsa el, hanem a TableExample2 osztályét – az iménti (a dialógusablakba, illetve a keret szövegterületére beírt) adatokkal mint parancssori paraméterekkel: java.exe -classpath "C:\Program░ Files\Java\j2sdk1.4.2_06\demo\jfc\TableExample\TableExample.jar;C:\Program░
10. oldal
Files\hsqldb\lib\hsqldb.jar" TableExample2░ "jdbc:hsqldb:hsql://localhost/xdb" "org.hsqldb.jdbcDriver" sa "" "CREATE░ TEXT TABLE Irszam (IRSZ Varchar, ST Varchar, MB Varchar, V Varchar, T_P░ Varchar, Ph Varchar, Cp Varchar, Kko Varchar, Fbl Varchar, Fbm Varchar, Kb░ Varchar, NemTudniMi Varchar, M Varchar, Telepules_neve Varchar, Posta_neve░ Varchar);SET TABLE Irszam SOURCE░ \"Orsz_irszam_orszagos.csv;ignore_first=true;encoding=Cp1250;fs=\t\"; SELECT * FROM Irszam;"
(az egész egy sorba írandó; szerencsésebb ezt a parancsot parancsállományba foglalni); az első szürke hátterű részt írtuk be korábban a Database URL: felirat mögé; a másodikat a Driver: felirat mögé; a harmadikat a User name: felirat mögé, a negyediket a Password: felirat mögé, az ötödiket meg a keret szövegterületére írtuk mint három külön SQL-utasítást. A TableExample szoftver négy osztályból áll: a TableExample, a JDBCAdapter, a TableMap és a TableSorter osztályból (a TableExample.jar állomány könyvtárának src nevű alkönyvtárában a forrásállományuk is ott van); a négyből a JDBCAdapter támaszkodik a JDBC API-ra. Az itt használt SET TABLE Irszam ... SOURCE ...
alakú SQL-utasítás nem szabványos; csak a HSQLDB használja táblázatos szövegállományok és HSQLBD-beli táblák összekapcsolására; ez nem járt semmi bajjal, mert a JDBC API csak továbbítja az SQL-utasításokat, értelmezni nem értelmezi őket; nem is volt semmi „kifogása” ennek az SQL-utasításnak a szabványostól való eltérése ellen. Hogyan kapcsolódtak egybe az összetevők
Emlékszünk még: négy adatot is meg kellett adnunk ahhoz (meg persze SQL-utasításokat), hogy végre láthassuk az adatforrás adatait: a Driver: felirat mellé azt írtuk be, hogy org.hsqldb.jdbcDriver; ez minden jel szerint egy osztály – és a hsqldb.jar állományban sokadmagával együtt meg is találjuk; ha még a hsqldb könyvtár src alkönyvtárában is utánanézünk, akkor kiderül, hogy a java.sql.Driver interfészt implementálja. Ez az osztály kapcsolja össze az alkalmazói szoftvert a JDBC API implementációjával – az ilyen szerepet játszó osztályokat meghajtóosztálynak nevezik. Eddig úgy fest, hogy az implementációból nem is kell további osztályokat ismernünk. a Database URL: felirat mellé azt írtuk be, hogy jdbc:hsqldb:hsql://localhost/xdb; ez csakugyan egy URL (Uniform Resource Locator – magyarul egységes erőforrás-megnevezés), bár alakra egy kicsit különbözik a weben szokásostól (mondjuk, attól, hogy http://www.oszk.hu); a jdbc:hsqldb:hsql rész azonban itt is egy protokollsorozat; a // utáni localhost rész arra utal, hogy kiszolgálóval kell kapcsolatba lépni, éspedig az alkalmazói szoftverrel egy gépen (de nem ugyanazon a virtuális gépen) futó kiszolgálóval, az xdb szimbolikus név pedig egy adatbázisra utal (ismerősnek tűnhet a kiszolgálót elindító parancsból). Láthatólag az URL teremt kapcsolatot a JDBC API implementációja és az adatforrást kezelő szoftver között. A JDBC API implementációját mostantól fogva meghajtónak mondjuk – vagy meghajtószoftvernek, ha félő, hogy valaki a meghajtó hallatán a meghajtóosztályra gondolna. megadtunk még két paramétert: egy felhasználóazonosítót és a hozzá tartozó jelszót; ezek az adatforrás védelmére szolgálnak. A JDBC API-ra támaszkodó szoftverek a JDBC API implementációján (más néven a meghajtón vagy meghajtószoftveren) és az adatforrást kezelő szoftveren át jutnak az adatforrás adataihoz. 11. oldal
A JDBC API-ra támaszkodó szoftvert a meghajtóosztály kapcsolja össze a JDBC API implementációjával, az adatforrást pedig az URL jelöli ki.
12. oldal
A második virtuális gépen fut
Az első virtuális gépen fut
TableExample.jar
mydb hsqldb.jar
org.hsqldb.jdbcDriver hsqldb.jar jdbc:hsqldb:hsql://localhost/xdb
2. ábra. A TableExample alkalmazás összekapcsolódása a HSQLDB Server kezelte szöveges állománnyal Megjegyzések Az URL az xdb szimbolikus névvel a szöveges állományt tartalmazó könyvtárra mutatott, és a HSQLDB voltaképpen két, abból a könyvtárból való adatforrást kezelt: magát a szöveges állományt és a CREATE utasítással létrehozott Irszam nevű adatbázistáblát (a kettő a HSQLDB-re jellemző SET utasítás révén kapcsolódott egymáshoz). Nemcsak olvasni lehet ebből a szöveges állományból, hanem (például az INSERT utasítással) írni is lehet bele; akinek kedve van, próbálja ki (a TableExample program a SELECT-től különböző utasításokat is eljuttatja a HSQLDB-nek, csak berzenkedik egy kicsit: kivételt ejt; de sebaj). Ebbe a táblázatba persze csak akkor kell beleírni, ha, mondjuk, új település vagy településrész alakul ki valahol és azt új irányítószámmal kell megjelölni (ez történt 1994-ben Budapesten Soroksár és Pesterzsébet szétválásával – Soroksár lett a XXIII. budapesti kerület); s egyéb változások is lehetségesek: például Szárliget 1999-ben elvált Fejér megyétől és Komárom-Esztergom megyéhez csatlakozott – ha a táblán ez a változás nem tükröződik is –; 1990-ben megváltozott jó néhány megyenév, például Komárom megyéből Komárom-Esztergom megye lett, Szolnokból Jász-Nagykun-Szolnok, Szabolcs-Szatmárból Szabolcs-Szatmár-Bereg stb. A kiszolgáló ugyanazon a gépen futott (csak más virtuális gépen), mint az alkalmazói szoftver meg a meghajtószoftver, de ez egyáltalán nem szükségszerű: TCP/IP-hálózatban futhatnak külön gépen is (és a kiszolgálókat külön gépen is szokás futtatni); ez csak az URL-ben jár változással: a localhost helyett a kiszolgálót futtató gép IP-címét kell beleírni. És az sem szükségszerű, hogy 13. oldal
a kiszolgáló Javában írt program legyen – például a MySQL, a PostgreSQL, az Oracle, az IBM, a Sybase vagy a Microsoft adatbázis-kezelője sem az –, de ez mit sem változtat a dolgon; csak az a fontos, hogy a meghajtószoftver „szót értsen” az adatforrás kezelőjével. A TableExample láthatólag támaszkodik metaadatokra is – különben honnan „tudta” volna, hogy hány sorból és oszlopból állítsa össze a táblázatot? Ha a TableExample táblázatának valamelyik oszlopfejlécére kattintunk az egérrel, akkor a táblázat sorai az abban az oszlopban érvényes sorrend szerint átrendeződnek (ha az M feliratú fejlécre kattintunk, akkor az az alatti nevek ábécésorrendben következnek majd egymásra; ha a Telepules_neve oszlopéra kattintunk, akkor meg a helységnevek, bár egy kissé furcsán: az Ő betűvel kezdődők jönnek utoljára; a TableExample és a másik három osztály forráskódjának birtokában próbáljuk kideríteni, hogy vajon miért?).
2.4 Egy kicsit megbolygatjuk az előző példát Az alkalmazói szoftver maradjon ugyanaz, mint eddig, de az adatforrást már megváltoztatjuk és másra cseréljük azt, ami közöttük volt – további tapasztalatszerzés végett. Feladat – Adatok táblázatos megjelenítése, még egyszer A JDBC API-ra támaszkodó program maradjon ugyanaz, az adatforrást változtassuk meg egy kicsit, de most tegyünk mást közéjük, mint eddig! Az adatforrás megváltoztatása
Az adatforrásban egy állományszerkesztővel (például a JBuilder szerkesztőjével) minden tabulátorkaraktert vesszőre (ASCII 44, hexadecimálisan 2C) karakterre cserélünk ki, és átírjuk az első sort, ilyesformán: IRSZ,ST,MB,V,T_P,Ph,Cp,Kko,Fbl,Fbm,Kb,NemTudniMi,M,Telepules_neve, Posta_neve
ezután elmentjük a megváltoztatott állományt (ugyanabba a könyvtárba, ahonnan vettük) – de új nevet adunk neki: azt, hogy Orsz_irszam_orszagos_.csv (a pont elé tehát becsempészünk egy aláhúzás-karaktert (ASCII 95, hexadecimálisan 5F). A most használt meghajtószoftver ugyanis nem „érti” (alapértelmezésben legalábbis nem), ha a mezők elválasztására nem a vesszőt használjuk. Meghajtószofver és adatforrás-kezelő egyben
Most nem két szoftvert iktatunk az alkalmazói szoftver JDBC API-ra támaszkodó felülete és az adatforrás közé, hanem csak egyet – az az egy majd mindent elintéz (legalábbis ami a mi igényeink kiszolgálását illeti). A http://sourceforge.net/projects/csvjdbc webhelyről letölthető tömörített állományban (2005 márciusában ez a csvjdbc-r0-10.zip állomány) egyebek mellett van egy CSVJDBC.JAR nevű állomány is; ezt fogjuk most felhasználni. Menjünk be a c:\Program Files könyvtárba, és onnan bontsuk ki a szokásos módon, a jar programmal a letöltött ZIP-állományt: jar xvf C:\Downloaded\CsvJdbc\csvjdbc-r0-10.zip
(feltéve, hogy a csvjdbc-r0-10.zip állomány a letöltéssel a C:\Downloaded\CsvJdbc könyvtárba került – ha máshová, akkor más útvonalat kell beírni; s ha a jar program nem látható a C:\Program Files könyvtárból, akkor eléje kell írni az útvonalát is). Most egyetlen Java virtuális gépet indítunk el – abból a könyvtárból, ahol az imént elmentett Orsz_irszam_orszagos_.csv nevű állomány van: java -classpath "c:\Program░
14. oldal
Files\Java\j2sdk1.4.2_06\demo\jfc\TableExample\TableExample.jar";"c:\Progra m Files\csvjdbc-r0-10\CSVJDBC.JAR"; TableExample
s ezzel megint feltűnik a már látott dialógusablak; ez alkalommal azonban így kell kitöltenünk a szövegmezőket:
(A Database URL: felirat után tehát ez áll: jdbc:relique:csv:. vagyis a végén a kettőspont után még jön egy pont – az utal a Java virtuális gép elindításának a helyére, egyszersmind az Orsz_irszam_orszagos_.csv állomány könyvtárára). Az ezután feltűnő keretben balra, fent levő szövegterületre írjuk be a következő SQL-utasítást: SELECT * FROM Orsz_irszam_orszagos_
(vigyázat, nem szabad pontosvesszőt írni a végére – ez ilyen SQL; próbáljuk ki: ha nem egy sorba írjuk az utasítást, akkor nem is érti). A tábla neve tehát az állománynév, a csv kiterjesztés (és az előtte álló pont karakter) nélkül. Ha megnyomjuk a Fetch feliratú gombot, újra előkerül a már ismert táblázat. jdbc:relique:csv:.
TableExample.jar
Orsz_irszam_orszagos_.csv CSVJDBC.JAR
org.relique.jdbc.csv.CsvDriver
3. ábra. A TableExample program és a szöveges állomány összekapcsolódása 15. oldal
Azonosság és különbség
Mindkét példában meg kellett adnunk meghajtóosztályt és URL-t; persze más-más meghajtóosztályt és URL-t, mert más szoftverek voltak az alkalmazói program és az adatforrás között. Meg kellett adnunk felhasználóazonosítót és jelszót is, bár ez a második esetben teljesen formális volt: a program bármit elfogadott volna. Az első példában a szöveges állományt önálló szoftver kezelte, és az más alkalmazói programot is kiszolgálhatott volna; a második példában a meghajtószoftver „összenőtt” a kezelőszoftverrel, a kettő persze egy virtuális gépen is futott, és, mondhatni, „kisajátította” az adatforrást. Ezzel az adatforrás beágyazódott magába az alkalmazásba – megváltoztak tehát a viszonyok: az adatforrás már nem önálló, hanem beépül az alkalmazói szoftverbe. Az ilyen adatforrásokat beágyazott adatforrásnak nevezik. Mint majd látni fogjuk, a HSQLDB által kezelt táblák is lehetnek beágyazott adatforrások, más szóval a HSQLDB is lehet beágyazott adatbázis-kezelő. Az első példában az SQL közvetítésével sok mindent megértettünk a HSQLBD-vel: például azt, hogy tabulátorkarakter választja el egymástól a mezőket stb.; a második példában ez nem ment: kénytelenek voltunk az adatforrást hozzáigazítani a meghajtóprogram igényeihez. Később majd látni fogjuk, hogy egy kis programozás árán másképp is segíthettünk volna magunkon – legalábbis részben. A két példában az SQL is eltért; a második adatforrás-kezelő SQL-je jóval szűkösebb – például az ORDER BY záradékot nem lehet benne használni.
Ha a JDBC API implementációja (vagyis a meghajtószoftver) és az adatforrást kezelő szoftver egybeépül, akkor az adatforrást magát beágyazott adatforrásnak mondják, a meghajtószoftver és az adatforrás-kezelő együttesét meg beágyazott adatforrás-kezelőnek.
16. oldal