[PHP/PDO] Database Connection ontwerp

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 11-07 17:24
Ik heb voor een project een DbConnection class nodig die de volgende dingen doet:
  • Connectie aanmaken met PDO. Er mag altijd maar 1 connectie zijn (Singleton)
  • De class moet gewone queries en prepared statements uit moeten kunnen voeren via PDO
  • De class moet ook een commit kunnen doen na een 'batch' van een aantal queries (dus bv. na 20 succesvolle queries volgt een commit)
De DbConnection class wordt door alle onderdelen van de applicatie gebruikt en is dus heel belangrijk.

Ik heb aan de hand hiervan het volgende UML klassediagram opgesteld:

Afbeeldingslocatie: http://i56.tinypic.com/30ucns5.png

De bedoeling is dus dat bijvoorbeeld execPrepStatement zoiets zou moeten worden:

PHP:
1
2
3
4
5
public static function execPrepStatement($sSql, $aParams, $bLog) {
    $oPdo = self::getInstance();
    $oQuery = $oPdo->prepare($sSql);
    $oQuery->execute($aParams);
}

Let op: code zuig ik net uit m'n duim, klopt niet helemaal met de UML en is misschien zelfs fout, maar het gaat om het idee

Een ander projectlid oppert voor het samenvoegen van de execPrepStatement en de execQuery methodes waardoor je zoiets moet doen:

PHP:
1
2
3
4
5
6
    $oPdo = DbConnection::getInstance();

    $oQuery = $oPdo->prepare("SELECT bla FROM bla WHERE bla = ?");
    $oQuery->bindParam(1, $bla, [extraparametersblabla]);
    
    DbConnection::execQuery($oQuery);


Als ik hem goed begreep althans.

Weer een ander idee was om gewoon geen methodes te maken voor het uitvoeren van queries, maar de DbConnection klasse alleen te gebruiken voor het ophalen van een PDO connectie en eventueel voor het committen van queries.

Een hoop inspiratie dus, het ene idee misschien nog slechter dan de ander, maar daar ben je dan ook tweedejaars student voor.

Wat ik graag zou willen weten is hoe jullie zo'n klasse in zouden richten en of er misschien rare ontwerpfouten inzitten :)

Acties:
  • 0 Henk 'm!

  • Jory
  • Registratie: Mei 2006
  • Laatst online: 20:32
PDO is niet een connectie, maar juist een abstractie van de verschillende mogelijkheden om te verbinden met een database.

De dingen die jij hier noemt, kan PDO sowieso allemaal al vanuit een eenvoudig te gebruiken interface. (De enige uitzondering hierop is het zijn van een SIngleton.)
Heb je dus goed gekeken naar wat PDO zelf al kan, en heb je hierop echt uitbreidingen nodig? (Dat PDO geen singleton is, kun je opvangen met depencancy injection, of door het in een registry te droppen.)

Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 11-07 17:24
Jory167 schreef op dinsdag 26 oktober 2010 @ 21:15:
PDO is niet een connectie, maar juist een abstractie van de verschillende mogelijkheden om te verbinden met een database.
Op het moment dat je iets van new PDO() uitvoert creëer je toch een connectie met de database? Dat is wat ik lees in de documentatie op http://www.php.net/manual/en/class.pdo.php. Sowieso hebben we natuurlijk telkens een object/connectie nodig die we door de gehele applicatie gebruiken.
De dingen die jij hier noemt, kan PDO sowieso allemaal al vanuit een eenvoudig te gebruiken interface. (De enige uitzondering hierop is het zijn van een SIngleton.)
Heb je dus goed gekeken naar wat PDO zelf al kan, en heb je hierop echt uitbreidingen nodig? (Dat PDO geen singleton is, kun je opvangen met depencancy injection, of door het in een registry te droppen.)
Daar heb je inderdaad wel een beetje gelijk in, dat was inderdaad ook wat ik hier beschreef:
Weer een ander idee was om gewoon geen methodes te maken voor het uitvoeren van queries, maar de DbConnection klasse alleen te gebruiken voor het ophalen van een PDO connectie en eventueel voor het committen van queries.
M'n projectleden waren het daar niet mee eens omdat ze een centrale plek wilden van waaruit queries uitgevoerd zouden worden zodat er nog andere dingen mee gedaan zouden kunnen worden (dingen zoals het loggen van succesvole/foute queries). Of dit gaat gebeuren weet ik nog niet precies, maar in dat opzicht is het juist handig om een speciale methode te hebben lijkt me?

Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 11-07 17:24
Nog meer mensen met een interessante visie op wat een DbConnection class zou moeten kunnen en hoe je dit het best in kunt richten? :)

Acties:
  • 0 Henk 'm!

Anoniem: 379656

Ben hier ook wel in geinteresseerd.
Is het sowieso mogelijk om dit een beetje veilig in een php script te laten runnen? Dit dan vooral gericht op de consistency en wat er bij uitval gebeurt.

Acties:
  • 0 Henk 'm!

  • SvMp
  • Registratie: September 2000
  • Niet online
Avalaxy schreef op donderdag 28 oktober 2010 @ 14:10:
Nog meer mensen met een interessante visie op wat een DbConnection class zou moeten kunnen en hoe je dit het best in kunt richten? :)
Ik heb een DBConnection class die ik overal gebruik. Deze gebruikt geen PDO, maar MySQLi. Inclusief support voor prepared statements. Bij interesse wil ik wel het e.e.a. posten, maar het is dus geen PDO.
Anoniem: 379656 schreef op vrijdag 29 oktober 2010 @ 11:38:
Ben hier ook wel in geinteresseerd.
Is het sowieso mogelijk om dit een beetje veilig in een php script te laten runnen? Dit dan vooral gericht op de consistency en wat er bij uitval gebeurt.
Minstens zo belangrijk is de error-handler van je project. Ik gebruik een simpele trigger_error. De classes van het project hoeven zich niet druk te maken om fouten. Een error-handler pakt het op. Tijdens development verschijnt uitgebreide info, de online versie vermeldt alleen dat er een probleem is en dat de website niet beschikbaar is.

Lastig is wel als tijdens een serie afhankelijke schrijf-bewerkingen de database wegvalt. Je krijgt dan inconsistentie. Een van de grootste uitdagingen imo.

[ Voor 48% gewijzigd door SvMp op 29-10-2010 11:48 ]


Acties:
  • 0 Henk 'm!

  • cariolive23
  • Registratie: Januari 2007
  • Laatst online: 18-10-2024
SvMp schreef op vrijdag 29 oktober 2010 @ 11:43:
Lastig is wel als tijdens een serie afhankelijke schrijf-bewerkingen de database wegvalt. Je krijgt dan inconsistentie. Een van de grootste uitdagingen imo.
Hier zijn toch lang geleden transactions voor uitgevonden? Of gebruik je engines van MySQL die geen transactions kennen?

Of doel jij op totaal iets anders?

Acties:
  • 0 Henk 'm!

  • Kalentum
  • Registratie: Juni 2004
  • Laatst online: 22:54
Ik zou, als ik een database object zou moeten maken op basis van PDO, alle custom functionaliteit in een gewone class zetten (die PDO extend of gebruikt). En een aparte singleton class die dan je eigen DbConnection object retourneert.

Dus iets als (Niet volledig)
PHP:
1
2
3
class DbConnection extends PDO {
   // eigen functies
}

en
PHP:
1
2
3
4
5
6
7
8
9
class DbSingleton {
    private static $_db = null;
    public static function getInstance() {
        if (is_null(self::_db)) {
            self::_db = new DbConnection();
        }
        return self::_db;
    }
}


Op die manier kun je je eigen DbConnection-class ook gebruiken als gewoon object ipv singleton.

Verder denk ik dat je DbConnection class niet zoveel van transacties hoeft te weten. Enige wat 'ie moet doen is de juiste SQL-statements versturen voor het starten, committen en rollbacken van je transacties, de class zelf weet niet op welk moment jij een commit wilt doen. Dus een drie methods als begin(), commit() en rollback() lijkt mij genoeg.

Overweeg ook het gebruik van een standaardoplossing (Zend_Db, de verschillende ORM-frameworks), waar veel dingen die wil of gaat willen al in zitten (query logging en profiling, transacties, makkelijke manier om queries met parameters uit te voeren).

[ Voor 6% gewijzigd door Kalentum op 31-10-2010 14:42 ]


Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 11-07 17:24
SvMp schreef op vrijdag 29 oktober 2010 @ 11:43:
[...]

Lastig is wel als tijdens een serie afhankelijke schrijf-bewerkingen de database wegvalt. Je krijgt dan inconsistentie. Een van de grootste uitdagingen imo.
Hiervoor willen we dus commits inplementeren die uitgevoerd worden na een batch van een x aantal queries :)
rutgerw schreef op zondag 31 oktober 2010 @ 14:42:
Ik zou, als ik een database object zou moeten maken op basis van PDO, alle custom functionaliteit in een gewone class zetten (die PDO extend of gebruikt). En een aparte singleton class die dan je eigen DbConnection object retourneert.

Dus iets als (Niet volledig)
PHP:
1
2
3
class DbConnection extends PDO {
   // eigen functies
}

en
PHP:
1
2
3
4
5
6
7
8
9
class DbSingleton {
    private static $_db = null;
    public static function getInstance() {
        if (is_null(self::_db)) {
            self::_db = new DbConnection();
        }
        return self::_db;
    }
}


Op die manier kun je je eigen DbConnection-class ook gebruiken als gewoon object ipv singleton.

Verder denk ik dat je DbConnection class niet zoveel van transacties hoeft te weten. Enige wat 'ie moet doen is de juiste SQL-statements versturen voor het starten, committen en rollbacken van je transacties, de class zelf weet niet op welk moment jij een commit wilt doen. Dus een drie methods als begin(), commit() en rollback() lijkt mij genoeg.

Overweeg ook het gebruik van een standaardoplossing (Zend_Db, de verschillende ORM-frameworks), waar veel dingen die wil of gaat willen al in zitten (query logging en profiling, transacties, makkelijke manier om queries met parameters uit te voeren).
Heel erg bedankt voor je posts, dit is info waar ik wat mee kan :) Zend Framework gebruiken we inderdaad ook, dus we zullen daar nog even naar kijken, maar anders bouwen we gewoon zelf iets :)

Acties:
  • 0 Henk 'm!

  • SvMp
  • Registratie: September 2000
  • Niet online
cariolive23 schreef op zondag 31 oktober 2010 @ 13:27:
[...]

Hier zijn toch lang geleden transactions voor uitgevonden? Of gebruik je engines van MySQL die geen transactions kennen?
Inderdaad. Tot nu toe is het in mijn projecten zo dat schrijven veel minder gebeurt dan lezen (1% - 99%) dus gebruik ik MyIsam. Die ondersteunt geen transactions.

[ Voor 4% gewijzigd door SvMp op 01-11-2010 07:09 ]


Acties:
  • 0 Henk 'm!

  • cariolive23
  • Registratie: Januari 2007
  • Laatst online: 18-10-2024
SvMp schreef op maandag 01 november 2010 @ 07:08:
[...]


Inderdaad. Tot nu toe is het in mijn projecten zo dat schrijven veel minder gebeurt dan lezen (1% - 99%) dus gebruik ik MyIsam. Die ondersteunt geen transactions.
Wanneer je kiest voor een omgeving die geen transactions ondersteund, dan is het toch logisch dat je met een corrupte database komt te zitten wanneer er dingen fout gaan? Bijzonder dat je dit nu omschrijft als een uitdaging, je kiest bewust voor deze (overbodige) problemen. 8)7

Dit kun je overigens ook niet in je code oplossen, je hebt database transactions nodig om dit soort problemen af te vangen.

Acties:
  • 0 Henk 'm!

  • SvMp
  • Registratie: September 2000
  • Niet online
@cariolive23: Wanneer is een probleem 'overbodig'? Als je deze kunt vermijden? Ja dat kan door voor InnoDB te kiezen. Maar dat heeft weer andere nadelen.

Je kunt het niet zo mooi oplossen als met transacties, maar er zijn wel de nodige work-arounds mogelijk zoals een systeem waarmee je inconsistenties kunt rechtzetten.

Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Avalaxy schreef op maandag 01 november 2010 @ 02:04:
[...]

Heel erg bedankt voor je posts, dit is info waar ik wat mee kan :) Zend Framework gebruiken we inderdaad ook, dus we zullen daar nog even naar kijken, maar anders bouwen we gewoon zelf iets :)
Als je al ZF gebruikt zou ik stoppen met zoeken. Zend_Db is voor simpele modellen "the way to go". Je krijgt wat moeite als je bijvoorbeeld i18n, versioning e.d. in je modellen op wilt nemen. Dan stap je relatief eenvoudig over naar Doctrine.

In de quickstart komt al snel naar voren hoe je Zend_Db gebruikt. Ook de integratie met een Db application resource voor Zend_Application is erg goed. Een paar simpele regeltjes in je application.ini en je database is klaar (voor MySql en vele andere platformen).

Acties:
  • 0 Henk 'm!

  • cariolive23
  • Registratie: Januari 2007
  • Laatst online: 18-10-2024
SvMp schreef op maandag 01 november 2010 @ 10:24:
@cariolive23: Wanneer is een probleem 'overbodig'? Als je deze kunt vermijden? Ja dat kan door voor InnoDB te kiezen. Maar dat heeft weer andere nadelen.
Er bestaan ook andere (betere) databases, dan hoef je niet meer te kiezen tussen verschillende engines binnen één database.
Je kunt het niet zo mooi oplossen als met transacties, maar er zijn wel de nodige work-arounds mogelijk zoals een systeem waarmee je inconsistenties kunt rechtzetten.
En hou zou je dat dan willen doen? Je bent bezig met een collectie schrijfacties en de server valt uit. Een deel van de data is nu wel correct opgeslagen/bijgewerkt/verwijderd, een ander deel niet. Hoe wil jij dan op een later moment gaan bepalen wat nu wel goed is gegaan en wat niet? Je weet niet eens meer waar je nu precies mee bezig was en waar je was gebleven: Dankzij de uitval van je servers ben je ook die gegevens kwijt. Je weet dus niet wat de oude situatie was en je weet niet wat de gewenste situatie is. Hoe wil je dan weer een consistente database krijgen? De backup van gisteravond terugzetten is dan zo'n beetje de enige "oplossing", al raak je dan ook weer data kwijt.

Met MyISAM is het zelfs goed mogelijk dat de tabellen onherstelbaar zijn beschadigd, ook dat ga je niet even fixen met een workaround.

Acties:
  • 0 Henk 'm!

  • Rikkos
  • Registratie: November 2010
  • Laatst online: 06-03 06:59
mithras schreef op maandag 01 november 2010 @ 10:30:
[...]
Als je al ZF gebruikt zou ik stoppen met zoeken. Zend_Db is voor simpele modellen "the way to go". Je krijgt wat moeite als je bijvoorbeeld i18n, versioning e.d. in je modellen op wilt nemen. Dan stap je relatief eenvoudig over naar Doctrine.

In de quickstart komt al snel naar voren hoe je Zend_Db gebruikt. Ook de integratie met een Db application resource voor Zend_Application is erg goed. Een paar simpele regeltjes in je application.ini en je database is klaar (voor MySql en vele andere platformen).
Het zit als volgt
We hebben 3 onderdelen van de gehele applicatie,

- Collector --> ZF niet ondersteund
- Converter --> ZF niet ondersteund
- Client --> ZF ondersteund.


(push) --> Collector (push) --> DB1 <---- (pull) Converter (push) ----> DB2 <--- (pull) Client

In de client zit inderdaad een defaultAdapter in die je heel simpel kan opvragen. Maar we hebben een class die maakt hem aan en set hem als default,. Het ZF zal dus die altijd gebruiken. . maar nu is vraag kan je die van buiten af benaderen. door niet ondersteunende zf applicaties. de collector en converter zijn dus onderdelen die niet via een webaddress te benaderen zijn. en dus zal het hele MVC model van zf nooit starten.

Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Nu praat je over een complexer systeem dan slechts een database abstraction layer met mogelijkheden voor prepared statements en transactions.

Geen idee wat precies je idee is van een "Collector", "Converter" en "Client", maar dat klinkt niet heel database achtig ;) Lijkt me meer een architectuur issue. Geen idee hoe het verder zit, maar als het losse applicaties zijn moet je maar eens gaan kijken naar communicatieprotocollen (Rest/Soap/XmlRpc etc). Als het drie losse taken zijn binnen je applicatie, zie ik eigenlijk niet echt een probleem :?

Acties:
  • 0 Henk 'm!

  • Kalentum
  • Registratie: Juni 2004
  • Laatst online: 22:54
Rikkos schreef op maandag 01 november 2010 @ 15:14:
In de client zit inderdaad een defaultAdapter in die je heel simpel kan opvragen. Maar we hebben een class die maakt hem aan en set hem als default,. Het ZF zal dus die altijd gebruiken. . maar nu is vraag kan je die van buiten af benaderen. door niet ondersteunende zf applicaties. de collector en converter zijn dus onderdelen die niet via een webaddress te benaderen zijn. en dus zal het hele MVC model van zf nooit starten.
Zend Framework steekt zo in elkaar dat je ook onderdelen kan gebruiken, zonder dat je de MVC structuur van Zend Framework gebruikt. Zend_Db kun je dus ook los gebruiken.
Pagina: 1