Adatbázisok kliens-szerver arhitektúrája
Copyright, 1996 © Dale Carnegie & Associates, Inc.
Az osztott feldogozást azért vezették be, hogy minikomputerekbıl álló rendszer tudja elvégezni ugyanazt a munkát, amit egy központi számítógép. Az adatokat a szerver (adatbázis-szerver) tárolja, az alkalmazások a kliens számítógépeken futnak. A szerver egy erıs számítógép kell legyen, mely több kliens számítógéptıl kap adatokat tárolásra, illetve lekérdezéseket, azért, hogy feldolgozza (processzálja) ıket, majd visszaküldje a kért adatokat a szerverrıl a kliens számítógépnek. A kliens számítógép lehet gyengébb is.
Az adatok helyességére vonatkozó feltételeket ajánlott a szerveren megszorítások formájában megadni és az adatbázis szerverre bízni ezek ellenırzését. Ha az adatok helyességének az ellenırzését a kliensen végeznénk, és egy felhasználó ODBC-n keresztül vagy OLE DB Provider-en keresztül férne az adatbázishoz, akkor tudna helytelen adatot az adatbázisba beszúrni, de mivel a szerverre bíztuk az adatok helyességének az ellenırzését, nem kerülhetnek semmiképp helytelen adatok az adatbázisba.
Eddig csak a direkt SQL-el foglalkoztunk SQL parancsok bekérésére és végrehajtására alkalmas SQL interpreter az alkalmazások esetében az SQL parancsok valamilyen szoftverfejlesztı eszközzel elkészített eljárások vagy függvények részeként lesznek felhasználva. Ezeket az alkalmazásokat általában valamilyen ún. befogadó nyelven (például C, Java, Cobol, Visual Basic, Delphi, Visual C++, stb.) készítik és egyes függvények vagy eljárások törzsében SQL utasításokat helyeznek el.
• •
• • •
Kliens oldal feladatai: Össze kell győjtse az összes szükséges információt, mielıtt kérelmet küldene a szervernek; A kliens csak a lekérdezések eredményeivel foglalkozzon, ne az alaptáblákkal. A lekérdezést hagyja a szerverre és csak az eredmény relációval dolgozzon. A szerver gyorsabb a lekérdezésekben, így kisebb táblákat kell szállítani a hálózaton; elvégezze az összes adat-kezelési mőveletet; az információ és az adat formázását a raportokban; felelıs az összes adat kiíratásáért a felhasználó felé;
A szerver oldal feladatai: • Mivel task orientált, képes kell legyen a mőveletek • • • • •
gyors elvégzésére; Nagy mennyiségő információ tárolása, módosítása, gyors keresés; Adatok helyességének az ellenırzése; A szerver létre kell hozza az eremények halmazát (result sets), amit a kliens alkalmazás kér; Elıfordul, hogy az adatbázis szervernek nincs felhasználói felülete, scriptet lehet csak futtatni; Nagyon fontos a biztonság, melyik felhasználó az adatbázis mely részéhez férhet hozzá;
Kliens-szerver szabványok
SQL2–ben egy SQL alkalmazásnak egyszer egy CONNECT operációt kell végeznie, hogy bekötıdjön a szerverhez, mielıtt bármilyen adatbázis mőveletet végezne. Ha létrejött a kapcsolat, az alkalmazás, vagyis a kliens, kiadhatja az SQL parancsait és a szerver végrehajthatja. A szabvány megengedi, hogy egy SQL kliens, mely már be van kötıdve egy szerverhez, bekötıdjön egy másik szerverhez is. Ha létrejön a második kapcsolat, az elsı kapcsolat “alvó” (dormant) lesz.
A kiadott SQL parancsokat a második szerver hajtja végre, mindaddig, míg a kliens: visszaállítja az elsı kapcsolatot (SET CONNECTION paranccsal); • egy más szerverhez kapcsolódik, amikor a második is “alvó” lesz. •
Egy adott pillanatban egy SQL kliensnek egy “aktív” kapcsolata van, és akárhány “alvó” kapcsolata lehet és minden parancs a klienstıl az aktív szerverhez irányul. Minden létrehozott kapcsolatot (legyen az aktív vagy alvó) meg kell szakítani a DISCONNECT mővelettel.
Kliens/szerver alkalmazások programozása Egy fontos része, hogy a relációs adatmodellen
alapuló adatbázis szerver halmaz szintő (set-level) rendszer. Az alkalmazás programozó nem csak úgy használja a szervert, mint egy hozzáférési utat és rekord szintő kód írását, hanem, amennyire az alkalmazás megengedi, halmazokra bontja a lekérdezéseket, különben túl sok üzenet lesz. Üzenetek száma csökkenthetı a tárolt eljárások (stored-procedure) mechanizmus segítségével. Egy tárolt eljárás egy elıfordított program, mely a szerver oldalon kerül tárolásra.
A tárolt eljárást kliens meghívja egy REMOTE PROCEDURE CALL (RPC) segítségével. Ha többször kell ugyanazt az SQL parancsot végrehajtani, érdemes az SQL parancsot az AB mellett tárolt eljárás formájában tárolni, melyet az ABKR lefordít, meghatározza a végrehajtási tervet és optimalizálja. Ha karaktersorként kapja meg az ABKR az SQL parancsot, minden alkalommal le kell fordítsa, kidolgozza a végrehajtási tervet és optimalizálja. Sokkal hatékonyabb meghívni a tárolt, lefordított eljárást.
A tárolt eljárások elınyei: • Egy eljárás megosztható több kliens között; • Jobb biztonság: bizonyos felhasználóknak
megadjuk a jogot, hogy meghívja ezeket, de ne változtathasson direkt az adatokon; • Optimalizálás végrehajtható ezen eljárások megírásakor, nem futtatáskor; • Elrejthetık a felhasználó elıl a rendszer, illetve adatbázis specifikus részletek, így nagyobb adatfüggetlenséget biztosítva.
A tárolt eljárások hátrányai:
nincs szabvány, minden rendszer másképp oldja meg. •
•
Az Oracle a PL/SQL nyelvet adja, mely egy procedurális kiterjesztése az SQL-nek harmadik generációs nyelvek jellemvonásaival (lásd az Oracle dokumentációt). Az MS SQL Server pedig a TRANSACTSQL-t (lásd az MS SQL Server dokumentációt).
Ha a lekérdezéseket tárolt eljárásokkal oldjuk meg, nagy a hatékonyságuk, viszont nem portábilisak (hordozható). Ha kicseréljük az ABKR-t, a tárolt eljárásokat át kell írjuk. Ha az SQL parancsokat a kliens alkalmazásban írjuk meg, akkor az ABKR-t kisebb munkával lecserélhetjük. Kérdés, hogy a hatékonyság a célunk, vagy a hordozhatóság?
A három szintő programozási modell esetén, mely az adat hozzáférési réteg (Data Access Layer - DAL), az üzleti logika réteg (Business Logic Layer - BLL) grafikus felhasználói felület (Graphical User Interface GUI)
a tárolt eljárások átvehetik a BLL feladatát és a DAL csak tárolt eljárások meghívásából áll. Ha nem használunk tárolt eljárásokat, akkor a DAL tartalmazza az összes SQL parancsot és az adatokat a BLL-nek már objektumok halmazaként vagy tömbök segítségével adjuk át, mely az alkalmazás logikáját programozza be. Ha egy alkalmazásnak vagy egy Internetes felülete és egy Windows-os felülete is, használhatják ugyanazt a BLL-t, vagy ugyanazokat a tárolt eljárásokat.
Befogadó nyelvbıl SQL Beágyazott SQL – programba épített SQL parancsok; SQL API (Application Programmming Interface) vagy CLI (Call Level Interface) –meghív speciális függvényeket, hogy az adatbázishoz hozzáférjen.
Beágyazott SQL a programozó feladata az adatfeldolgozó algoritmusnak a befogadó nyelven való megfogalmazása és a beágyazott SQL utasítások programba szerkesztése. Ezután a programot egy ún. elıfeldolgozó (prekompilátor) program átalakítja úgy, hogy a programba beágyazott SQL utasításokat a befogadó nyelv utasításaira alakítják. A folyamat során létrehozott befogadó nyelvi utasítások meghívhatnak például olyan függvényeket, amelyek paraméterükben egy SQL utasítást várnak karakterlánc formában és képesek a paraméterben kapott SQL utasításokat végrehajtani.
Ezután a tisztán befogadó nyelven írt forrásprogramot a befogadó nyelvi fordító lefordítja. Az elkészült modulokat össze kell szerkeszteni az adatbázis-kezelı rendszer gyártója által forgalmazott programkönytárakkal, melyek tartalmazzák az elıbb említett függvények implementációját, amelyek képesek karakterlánc formájában leírt SQL utasítások végrehajtására. Oracle adja a PRO*C/C++, PRO*CoBoL, PRO*Fortran elıfordítókat. Az MS SQL Server is ad C elıfordítót.
Az SQL nyelv adatmodellje lényegesen különbözik egy hagyományos programozási nyelv adatmodelljétıl. Az SQL magját a halmazorientált relációs adatmodell képezi, nem támogatja a tömb, mutató fogalmat a programozási nyelvek az elemi adattípusokat és a típuskonstruktorokat támogatják csak, a halmaz fogalmát nem.
Ahhoz, hogy kommunikálni tudjanak egymás között a befogadó nyelv és az SQL szükség van egy interfészre. Az adatbázis eléréséért felelıs SQL utasítások és a befogadó nyelven megírt alkalmazói program utasításai közti adatcsere a befogadó nyelven deklarált változókon keresztül történhet, ezeket megosztott eléréső változóknak nevezzük.
Pelda Diákok (BeiktatásiSzám, Név, SzemSzám, Cím, SzületésiDatum, CsopKod, Átlag); Csoportok (CsopKod, Evfolyam, SzakKod); A deklarációs rész a következı: EXEC SQL BEGIN DECLARE SECTION; char CsopK[3], int Ev, char SzakK[2]; char SQLSTATE[6]; EXEC SQL END DECLARE SECTION;
void beolvasCsoport() { EXEC SQL BEGIN DECLARE SECTION; char CsopK[3], int Ev, char SzakK[2]; char SQLSTATE[6]; EXEC SQL END DECLARE SECTION; /* bekér a felhasználótól egy csoport kódot,egy évfolyamot és egy szak kódot és azokat eltárolja a CsopK, Ev, illetve SzakK változókban */ EXEC SQL INSERT INTO Csoportok (CsopKod, Evfolyam, SzakKod) VALUES (:CsopK, :Ev, :SzakK); }
SELECT SQL lekérdezések általában nem ágyazhatók be mivel egy halmazt adnak vissza eredményül, és a legtöbb programozási nyelv ezt nem tudja kezelni. Megoldás: Az egyetlen sort eredményezı lekérdezések a lekérdezés eredményeként létrejött eredménysort eltárolhatják változókba, az eredménysor egyes komponensei külön-külön változókba lesznek elhelyezve. Egy olyan lekérdezésnek, amely egynél több sort (sorhalmazt) ad vissza eredményül egy sormutatót definiálunk. A sormutató befutja az eredményreláció összes sorát és egy-egy eredménysor egyes komponenseit külön-külön változókba elhelyezve juttatjuk el az adatokat a befogadó programnak.
Egyetlen sort eredményezı lekérdezések: void CsoportAtlag () { EXEC SQL BEGIN DECLARE SECTION; char CsopK[3], real CsopAtlag; char SQLSTATE[6]; EXEC SQL END DECLARE SECTION; /* bekér a felhasználótól egy csoport kódot, és eltárolja a CsopK változóban */
EXEC SQL SELECT AVG(Atlag) INTO :CsopAtlag FROM Csoportok WHERE CsopKod = :CsopK; /* kiíratjuk a CsopAtlag értékét, ha az SQLSTATE nem jelez hibát */ }
több sort eredményezı lekérdezések # define NINCS_TOBB-SOR ! (strcmp(SQLSTATE, "02000")) void KiirInfo3() { EXEC SQL BEGIN DECLARE SECTION; char nev[50]; char CsopK[3]; char cim [60]; char SQLSTATE[6]; EXEC SQL END DECLARE SECTION;
EXEC SQL DECLARE Info3Sorm CURSOR FOR SELECT CsopKod, Nev, Cim FROM Diákok, Csoportok WHERE Diakok.CsopKod=Csoportok.CsopKod and Evfolyam = 3 and (SzakKod= IROR SzakKod= IM ); EXEC SQL OPEN Info3Sorm; while(1) { EXEC SQL FETCH FROM Info3Sorm INTO :CsopK, :nev, :cim;
If (NINCS_TOBB_SOR) break; printf("%s %s %s\n", CsopK, nev, cim); } EXEC SQL CLOSE Info3Sorm; }
SQL API • ODBC ( Open DataBase Conectivity ) – Microsoft
írta a Windows alkalmazásokhoz.
• Microsoft OLE DB provider, illetve ADO (ActiveX
Data Objects);
• SAG : SQL Acces Group írta, ismert X/Open CLI
néven is; • IDAPI (Integrated Database Application Programing
Interface) Borland, IBM, Novell, Wordperfect írta együtt; • JDBC (Java Database Conectivity) - SUN.
Egy ilyen univerzális környezet (mint az ODBC vagy OLE DB) úgy jelenik meg, mint egy eljárás könyvtár, mely a következıket kell tartalmazza: • Connect / deconect – kapcsolatot létesít /megszakít egy adatforráshoz; • SQL parancs küldése és végrehajtása; • Annak a helynek a meghatározása, ahová az SQL
eredményét vagy valami üzenetet küldeni kell; • Beszámolás arról, hogy hogyan fejezıdött be egy
SQL parancs végrehajtása – hiba kódok; • Ahhoz, hogy adat cserét tudjanak végezni, szükség
van szabványos adattípusokra.
Az SQL parancsot karaktersorként kapja meg a szerver, analizálja (ellenırzi a helyességét), meghatároz egy végrehajtási tervet, optimalizálja azt (felhasználva információkat az adatbázisból, esetleg indexeket is használ), meghatározza a választ és visszaküldi a választ. Különbözı típusú driverek léteznek: • Nem adatbázis szervernek megfelelı driver (Access, Foxpro, Excel, Btrieve, Paradox, DBase) – az SQL parancsot maga a driver végzi el (keres az adatbázisban, küldi az eredményt); • Adatbázis szervernek (Oracle, MS SQL Server) megfelelı driver. A driver ellenırzi az SQL parancsot, de végrehajtásra az adatbázis szerverhez küldi.