DAO – adatbázisműveletek objektumokkal
Talán egy középhaladó (PHP) programozó egyik legnagyobb problémája a saját fejlesztésnél az adatbázis-műveletek kezelése. Sokszor sokféle lekérdezést írunk vagy sokféleképpen hivatkozunk egy bizonyos adathalmazra, így bonyolulttá válik bármiféle gyorstárazás vagy egységes elérés implementálása. Itt siet segítségünkre a DAO, avagy az objektumok adatbázisba mentésének módszere.
A dolog voltaképpen egyszerű, de ellentmondásos. Nézzük a következő vázat:Mint látható, az adatok betöltése és mentése egységesen történik. Ezzel megspóroltunk magunknak egy rakás munkát, hiszen amint kiolvastuk az adatbázisból az adatokat, nem tömböket kell pakolgatnunk az alkalmazásunkban, hanem egyetlen objektumot, annak minden segédfüggvényével tologathatunk, amerre jól esik. Ezen felül, ha úgy tetszik, a
Ellentmondásosnak tűnhet teljesítmény szempontjából ez a módszer, hiszen a keresések során ki kell válogatnunk a kívánt objektum azonosítóit, majd végig kell példányosítanunk az összeset. Gondoljunk azonban arra, hogy a
Még egy utolsó megjegyzés a témához, aztán hagyom a kedves olvasó kreativitását szárnyalni. Ugyan már nem szigorúan a DAO témakör, de tovább fokozhatjuk a fejlesztési hatékonyságot, ha a tipikus keresésekre absztrakt osztályt gyártunk (pl. az egy táblás keresésekhez
Kellemes fejlesztést.
■ A dolog voltaképpen egyszerű, de ellentmondásos. Nézzük a következő vázat:
<?php
class MyDataObject implements DAO
{
protected $vars = array(
"id" => "int",
"myvar" => "string"
);
protected $data = array();
function load($id)
{
$data = query_my_database("SELECT * FROM mytable WHERE id = ...");
if (isset($data[0])) {
$this->data = $data;
}
}
function save($new = false)
{
if ($new || !$this->data['id']) {
query_my_database("INSERT INTO mytable ...");
} else {
query_my_database("UPDATE mytable ...");
}
}
function __get($var)
{
if (isset($this->vars[$var]) {
return $this->data[$var];
} else {
return null;
}
}
function __set($var, $value)
{
if (isset($this->vars[$var]) {
$this->data[$var] = $value;
} else {
throw new Exception();
}
}
}
__set
függvénybe beépíthetjük a mindenféle ellenőrzést, aminek köszönhetően az egységbe zárás elvét valósítjuk meg.Ellentmondásosnak tűnhet teljesítmény szempontjából ez a módszer, hiszen a keresések során ki kell válogatnunk a kívánt objektum azonosítóit, majd végig kell példányosítanunk az összeset. Gondoljunk azonban arra, hogy a
save
illetve load
függvény kiváló pontot nyújt a gyorstárazáshoz, hiszen az egész objektumot egy az egyben be tudjuk tenni memóriába, kiolvasni onnan illetve változáskor kiütni.Még egy utolsó megjegyzés a témához, aztán hagyom a kedves olvasó kreativitását szárnyalni. Ugyan már nem szigorúan a DAO témakör, de tovább fokozhatjuk a fejlesztési hatékonyságot, ha a tipikus keresésekre absztrakt osztályt gyártunk (pl. az egy táblás keresésekhez
DAOSimpleSearch
), aminek elég belöknünk egy paraméterhalmazt, kimenetként megkapjuk a lepéldányosított osztályok tömbjét/iterátorát.Kellemes fejlesztést.
...
-cs-
Sanyi
Miért kellene?
A cikket nem komplett, kész megoldásnak használtam, sokkal inkább gondolat indítónak, látókör tágításnak. Hogy mit csinálsz belőle, az teljesen a Te kezedben van.
hat szeretnem a DAO ertelmet latni, de nehezen megy
bocs, de ha protectednek allitom a $vars-t, akkor azt kivulrol ugyan sose fogom tudni allitani, kiveve persze ha __get() fuggvennyel megkerulom ezt vagy irok egy getter-settert hozza.
Tudom, hogy gondolatinditonak szantad, de en valahogy semerre nem tudtam elindulni a menten, hogy mi tortenik az osszetett lekerdezesek eseten. Ezek tobszoros joinokat, beagyazott selecteket is tartalmaznak. Az insert, update, delete operaciok sajnos nagyon atomiak.
Lehet mar eleget programoztam mara es elfaradtam, holnap reggel futok vele meg egy kort :-)
-cs-
Sanyi
Jó az
gondolatindító kifogások
Az alapelveket érdekesnek, esetenként kimondottan hasznosnak látom. Olyan példákra gondolok, amikor az objektumokon egyszerű műveleteket végzek. Előveszem, módosítom, törlöm.
A valós életben azonban egyre reálisabb az igény ennél lényegesen összetettebb összefüggések kezelésére. Többféle 'objektum' összefüggő adataiban keresés, szűrés megvalósítását még nem látom, hogy a fenti megoldás milyen kiegészítésekkel képes megvalósítani. Csak egy pár évvel ezelőtti problémakör egy részét kiemelve:
Egy verseny lebonyolító rendszerben vannak versenyzők, vannak különböző kategóriákban (kor/nem/súly) kiírt verseny számok amikre a versenyző leadhatja nevezését. A nevezés lezárása után sorsolás következik, aminek következtében kieséses alapon a versenyzők mérkőzéseket játszanak egymással. A végén minden versenyszámban 1. 2. 3. helyezettet hirdetnek.
A problémakörből tényleg csak pár feladatot kiemelve:
Egy adott versenyszámban induló versenyzők listázása
Egy adott versenyző mérkőzéseinek listázása
Egy adott versenyszám aktuális, lejátszható mérkőzései (több ágon indított párhuzamos futtatás mellett)
Nem részletezem tovább. A feladat leírásban kiemeltem azokat az entitásokat amiket érdemesnek tartok a fenti példa szerint objektumként kezelni. Hogyan támogatja hatékonyan az általad vázolt modell az itt leírt problémák megoldását?
Őszintén örülnék neki, ha ezt egy beszélgetésindító hozzászólásként értékelnéd :) várom a válaszodat.
+1
Én annyit kérdeznék, hogy az elején a változótípusok megadásának mi a célja?
Nyilván
nyilván, így önmagában meglehetősen kevés haszna van. Két érvet tudnék csatasorba állítani a dolog mellett. Az egyik a szervezési. Ha az ember olyan adatszerkezettel dolgozik, amiben jól definiált objektumok vannak (tehát mint egy blogbejegyzés) akkor könnyebb fejleszteni. Gondolj bele, ha egy bejegyzés hozzászólásait akarom kilistázni, akkor megírom a queryt, ha szerkeszteni akarom, megírom a queryt, ha ki akarom listázni a legújabb hozzászólásokat, megírom a queryt, aztán ha változik az adatszerkezet, akkor írom át az összeset. Ez akkor tud nagyon hatékony lenni, ha az ember a kereséseket is összefogja, mondjuk például egy kereső osztályba, aminek meg lehet mondani, hogy ennek a mezőnek legyen ennyi az értéke, az legyen nagyob ennyinél, stb. majd egy függvénnyel összeállítja a queryt és végigpéldányosított osztályokat kapunk.
Namost, ez teljesen nyilvánvalóan nem minden esetben hatékony. Ha olyan adatszerkezeted van, ami nem definiálható jól objektumokként vagy egész egyszerűen nincs szükséged ilyen jellegű absztrakcióra, akkor tök fölösleges erölködni vele. Erről minig ez a cikk jut eszembe.
A másik érvem a cachelés. Sokkal könnyebb az objektumokat cacheélni, ha nem kell 60 helyen átírni őket. Ennél tovább megyek, ha az ember savekor kiüti őket, nincs is meg az probléma, hogy egyes elemek esetleg még régiként vannak a cacheben.
Ami a változó típusokat illeti, az alapján alapvető formai validációkat lehet beépíteni a __set metódusba. Ezt itt nem valósítottam meg, de minimális erölködéssel beletehető.
Fordítsunk
Gyakorlatilag ez egy egyszerű select:
Ezt nem biztos, hogy értem. Le tudod fordítani a fentiek mintájára queryre?
Lényeg
a varazsszó:
vannak jo orm megoldasok php-hez. lattam mar belso fejlesztestut is es vannak opensource fejlesztesek is.
ilyenek pl a propel illetve a doctrine.
elegge kiforrottak, tamogatjak a relaciokat (1-1, 1-n, n-m), a beagyazott objektumokat, entitasokat, stb...
ami a closedben (belso fejlesztes) tetszett az a __get() es __set() otletes hasznalata:
phpdoc doksival es reflection apival karoltve tipusvizsgalat volt belove...
tetszett, bar ez megint jo kis bottleneck lehet. Ha jol emlekszem, akkor az ezComponents is hasznal hasonlo megoldast.
egyebkent szvsz erdemes lehet a fenti megoldasba belekeverni egy kis SPL-t mert az viszont teljesitmeny javulast hozhat, pl az objektumok iteralasa soran
egyebkent: igazaból ha nem natív - pl. pdo queryket (az is kepes visszaadni kozvetlen sdtClass tipusu objektumot) - hasznalsz akkor a teljesitmeny az mindenfelekeppen roszabb lesz. de nem is arrol szol a dolog. boven karpotolnak az egyeb feature-ok
ezComponents
A doktrint is hasznaltam egy peldaprojekt erejeig, de a dokumentacio nagyon rossz. Abszolut nem az aktualis verziohoz keszult, anno es nehezen boldogultam vele az elejen, ezert hagytam is a hasznalatat. A yaml az jo volt, de szinten doksi az szinte hasznalhatatlan volt hozza.
A propel, ha jol emlekszem mar abbahagytak.
En a DAO-t inkabb egy Factory patternnel egybekotve illetve sokeroforrasos (xml,faltfile,db) kezeles eseten nagyon is jol el tudom kepzelni. Persze a bonyolultabb lekerdezeseket azert mar kezzel kene megirni, vagy egy orm szeru osztalycsomagot letrehozni neki.
-cs-
Sanyi
ORM-ek
A bonyolult lekérdezéseket pedig általában tényleg SQL-ben kell megírni, de ez egyáltalán nem baj - sőt... :) A legtöbbször mégis célszerű ORM-et használni, legalábbis én még a legkisebb projekthez is használok - nem beszélve arról, hogy a fejlett ORM-ek mindegyike támogatja a közvetlen SQL parancsok futtatását is (a Doctrine szintaxisa pedig eleve hasnlít az SQl-hez - a neve DQL).
A házilag barkácsolt ORM-ben nem tudok hinni :) sok szörnyűséget láttam már ezen a téren... :-)
Használni, módjával
Mindig lesznek esetek, amikor egyedileg kell lefejleszteni, mert az emberek 80-90%-ának gyártott megoldás nem jó és ezért szeretem, ha valaki saját kútfőből is tud alkotni, de ha kell, tud kész szoftvert is használni. (Pl. LDAPhoz nem láttam még annyira ORM megoldást hirdetve. Persze, biztos van.)
Hmm
Nem
Destruct
Ezt a __set-be illesztett kóddal, ami menti egy tömbbe, hogy milyen paraméterek módosultak elég egyszerűen meg lehet oldani.
Próbáld ki
Igaz
Set-eléskor?
Valóban
Nincs semmi problémám az
Valóban
Sziasztok! Először is mint
Először is mint felhasználó új vagyok, bár már régóta olvasgatom a Weblabort. A cikkért először is gratulálok, ugyanis a kreativitást és a gondolkodásmódot fejleszti a webfejlesztésben.
Hozzászólásokra reagálva:
A hozzászólásokat végig olvastam, és nem értek azokkal egyet, akik azt mondják, hogy kár ilyenre időt fordítani. Az tény, hogy van rájuk szép és open source megoldás, de annak ellenére az elv is érdekelhet és valakit mint például engem érdekelhet.Miért is jó ez a megoldás amit a cikk írója írt:
dolgozhat és ezt eltakarja a feljesztő elő (view egy szép megoldás).
Egyéni ötletek
A szakdolgozatomban én is írtam egy DAO, DTO -okat kezelő struktúrát, bár nekem ketté válik a DAO és a DTO objektum. A DAO csak adatbázis műveletek végez és DTO-okat hoz létre míg a DTO a rekordra vonatkozó struktúrát és adatokat tárolja melyeken a fejlesztő dolgozik, amikor végez vele átadja a DAO-nek, hogy mentse le és törölje .... A DAO a mentéskor ellenőrzi, hogy az adatok megfelelőek e, kötelező mező kivan e töltve megfelelő az érték stb... (ezeket az ellenőrzéseket mind adatbázisbó szedi).Ha valakit érdekel az én megoldásom, igaz csak PostgreSQL-re működik jelenleg, akkor a szakdolgozatom eme részét feltudom tenni ide cikk formájában. Persze akkor csak ha van rá érdeklődő!
A cikk írójának meg gratulálok, csak így tovább és a lelkesedésed ne apadjon le :-)
Köszönöm
először és köszönöm és üdv köreinkben.
Egyetlen megjegyzést tennék: tekintve, hogy a felvázolt DAO megoldás osztályonként egyetlen egy entitást / objektumot kezel, szerintem, a where feltételt nem célszerű belevenni. Sokkal jobbnak / használhatóbbnak gondolol azt a megoldást, ha van egy külön kereső osztály hozzá. Ha ugyanis mindenféle feltételt is megengedsz, a DAO osztályod a maga egyszerűségét hirtelen elveszti.
Egyébként persze, hogy érdekel a megoldásod. Szerintem, ha egy cikk hosszára le tudod rövidíteni, akkor tedd föl, vagy blogmarkként küldd be!
A cikket elküldöm a
A dolgozatomba 3 rész található ami érdekelheti az embereket:
1. Egy Adatbázist kezelő vékony réteg (singleton osztály gyakorlatilag csak az adatok vissza szedésében add keretet PSQL-ben (de MySql-re is átírható 2 perc alatt))
2. DAOBase, DTO struktúra melyről már szóltam
3. Egy egyedi fejlesztésű MVC (Java GUI-ra hasonlít Komponensek, Kontínerek, Vezérlők)
Mind a 3 rész érdekes lehet webfejlesztők számára! Amint végeztem a védéssel elküldöm!
Oks
Bocs, hogy mindig ezzel hozakodok elő
Korábban használtam már saját fejlesztésű DAO-t, a CakePHP-ból és a Ruby-ból ihletett átiratokat és ADOdb-t is, de eddig a ZF megoldása tetszik a legjobban.
Érdemes megnézni.
Alább egy kis példa. De ezt tulajdonképpen bármelyik ZF-es tutorial is leírja, de így azért mégiscsak szemléletesebb, mint egy link.
config.xml
Btw... valamit csináljatok légyszi a colorer-rel, mert IE8 alatt teljesen elveszti a formázást...
Halmozás
Pár hónapja én is Zend-et használok, és nekem is teljesen bejött az adatbázis elérése, használata.
Ami szerintem egy nagyon jó gondolat, az a lekérdezések "összerakása" halmozással.
Konkrétan erre a részletre gondolok:
- sokkal olvashatóbb a kód tőle
- elfedi az adatbázis, amin fut a kód, tehát az adatbázis specifikus szintaktikát is (valamilyen szinten) támogatja
- egyszerű paramétertől függő lekérdezéseket írni; itt például erre a részre gondolok:
Query-vel mi a baj?
Mondjuk átláthatóság véget szerintem azért ez olvashatóbb:
Férre ne értsd, de szerintem ez megint konvenció kérdése. Nekem mondjuk egyik megoldással sincs bajom, de bevallom a fenti lekérdezést én gyorsabban átlátom!
Engem is érdekelne
Nézegetem én is a frameworkoket, de néha olyan érzésem van, hogy időnként kitalálnak mindent, csakhogy kiváltsák azt, amit egyébként az adott feladatra találtak ki.
Refactoring és
pl:
Szerintem az így tárolt utasítások is teljesen korrektek, csak itt is konvenciókat kell hozni.
Összetettebb lekérdezésekhez meg Modelt kell használni a fenti DAO leírás egy kis átalakítással könnyen lehet modell.
A query-vel semmi baj sincs,
Szerintem egyszerűen kényelmesebb a halmozásos megoldás, de persze ízlések és pofonok! :-)
Két dolgot tudnék előnyként felhozni:
- nehezebb elrontani egy-egy lekérdést: jó esetben már az IDE szól, hogyha elgépelsz 1-1 halmozott függvényt, nem pedig egy "SELETC"-et írva rejtve marad a hiba, amíg le nem próbálod futtatni
- könnyebb, hogy nem string-műveletek kell végezned ha mondjuk egy-egy új szűrőfeltételt szeretnél hozzátenni a lekérdezéshez, vagy egy új oszlopot, stb. Például pont mostanában jött elő, hogy egy form-on van rengeteg keresőmező. Ha a keresőmezők üresek, akkor természetesen nem kell az üres string-nek illeszkedni semelyik adatbázisbeli oszlopra. A halmozásos módszerrel egyszerűen hozzá tudsz még venni egy where feltételt a select objektumodhoz, nem kell olyanokkal törődnöd, hogy van-e már benne where feltétel, és akkor AND-et kell bele raknod, vagy esetleg egy default "1=1"-et mindenképpen beleraknod.
Konkrétan erre gondolok:
Természetesen ha inkább a kézzel megírt lekéredzéseket részesíti előnyben az ember, a Zend azt is le tudja kezelni! :-)
Query kiírása:
Zend-ben van beépített profiler, amivel ki lehet íratni a lekérdezéseket, szóval nem vesznek el :-)
Igazából annyi előnye van, hogy -szerintem- sokkal gyorsabban lehet benne fejleszteni.
Anno mi framework nélkül kezdtünk el egy nagyobb project-et. Amikor vége lett, valamiért előkerült a Zend, és egyik ámulatból a másikba estem, amikor visszaemlékeztem, hogy amik benne vannak a Zend-ben alalpból, azokat mind kézzel kellett megírni korábban (MVC, form-kezelés, adatbázis elérés, lekérdezésekhez profiler, layout-ok, multipart e-mail küldés, pdf generálás, stb.)
Mennyit eszik százon?
Nem hiszem, hogy érzékelhető a lassúlás felhasználói szemmel
Cáfoljatok meg, de szerintem ez nem lehet érezhető, lényegi lassulás egy oldal betöltésénél (kivéve talán a _nagyon_ extrém eseteket).
Konkrétan arra gondolok, hogy nagyjából az alábbi dolgok befolyásolják egy oldal megjelenését:
- sokáig futó adatbázis lekérdezések
- nem optimális php kód
- lassú hálózat
- az oldal renderelése
Eddig tapasztalataim szerint az esetek 99%-ban nem a php kód lassúsága volt szűk keresztmetszet a sebességgel kapcsolatban. Vagy másképp fogalmazva, hacsak nincsen _nagyon_ elrontva a php kód, akkor nagy valószínűséggel az a leggyorsabb a fentiek közül. A ZF kódját szerintem nem rontották el nagyon :-)
Szóval szerintem az optimalizálást a másik hárommal érdemes kezdeni, és utána esetleg a php kódra is érdemes ránézni. Ez persze nem azt jelenti, hogy a php kód nem fontos, hogy optimális legyen, inkább azt, hogy a másik három nagyságrendekkel jobban lassíthat.
(az persze más kérdés, hogy magának egy framework-nek a használata mennyit lassít egy oldal megjelenésén, illetve nagy terhelés/sok párhuzamos lekérdezésnél mellett biztosan lassít ...)
+1
A vas meg egyébként is elhanyagolható szerintem a sávszélhez képest nagyobb oldalaknál.
Az adatbázis cache...
Ahogy írták is, ki lehet íratni
Régóta
Gyártószkriptekkel hozom létre az osztályokat, paramétertömböket felhasználva alapul, még fejlesztésidőben.
Gyorsabban futó, és flexibilisebb megoldás szerintem mint az extends.
Amúgy meg a sebesség miatt nem kell aggódni, mert eltörpül az SQL kapcsolat+lekérdezés sebességéhez viszonyítva.
a sajatod?
A sajatodrol van szo, vagy a mar letezo megoldasokrol.
Anno keszitettem egy kis tesztet. Propel, Doctrine es PDO-n keresztul kerdeztem le ugyanazt. Az eredmeny nalam a PDO javara 10x kevesebb futasi ido, 10x kevesebb memoriahasznalat mellett.
...
-cs-
Sanyi
igen
Amúgy nemrég tettem át PDO-ra.