mmofacts.com

Objektorientierung und Datenbankzugriffe

gepostet vor 14 Jahre, 5 Monate von Phoenix1988

Hallo,

ich hab im Moment ein Problem die Objektorientierung mit einem effizienten Datenzugriff zu verbinden.
Mir ist schon klar das OO zwangsläufig langsamer ist als prozeduale Programmierung, aber ich würde den Geschwindigkeitsnachteil gerne so gering wie möglich halten.

Von der reinen OO-Logik gesehen habe ich jetzt beispielsweise ein Objekt Feld, welches ein Feld auf meiner Karte repräsentiert. Innerhalb des Objektes habe ich Methoden, die die einzelnen Attribute des Feldes befühlen. Dabei ist ein Datenbankzugriff notwendig.
Habe ich jetzt einen Ausschnitt aus meiner Karte, werden dort beispielsweise 25 Felder angezeigt. 25 Datenbankzugriffe sind nicht denkbar.
Wie löse ich das Problem am effizientesten?

Mein Ansatz ist im Moment eine Redundanz zu schaffen. Zum einen habe ich das Objekt Feld, welches sich über Methoden die kompletten eigenen Daten aus der Datenbank beschaffen kann.
Zum anderen bietet das Objekt auch Methoden an, um alle Attribute manuell zusetzen. Eine Feld-Factory kann Daten mehrerer Felder aus der Felddatenbank holen und die entsprechenden Feld-Objekte erstellen und befüllen.
Gibt es hierfür vielleicht einen eleganteren Ansatz?

Zum Zweiten ist es bei meinem Spieler-Objekt aufgrund der Vererbungshierarchie so, dass um alle Daten zu füllen mehrere Datenbankzugriffe nötig sind. Rein logisch gesehen ist ein Spieler in meinem Fall eine Spezialisierung eines Teilnehmers. Der Spieler stellt die gerade eingeloggte Person dar, während Teilnehmer zum Beispiel die Gegner sind.
Viele Teilnehmer-Eigenschaften (Liste mit Standorten, allgemeine Daten etc.) gelten auch für den Spieler, werden hier noch ergänzt.
Sollte ich hier der Performance zu liebe darauf verzichten die geerbten Methoden zu nutzen und alles in einem Datenbankzugriff realisieren? Also Performance oder Wartbarkeit?

Ich versuche die Datenbankzugriffe zu minimieren, allerdings stehe ich oft vor dem Problem, dass ich vieles dann mehrfach implementieren muss, da ich auch nicht immer alle Daten brauche und dann ist ein Join über mehrere Tabellen doch ineffizient. Es endet mit Redundanzen im Code. Natürlich lässt sich das nicht vermeiden, aber vielleicht kennt ihr ja bessere Wege.
Über Vorschläge und Diskussionen würde ich mich freuen :)

gepostet vor 14 Jahre, 5 Monate von Phoscur

Allgemein umfasst das Thema, dass du gerade ansprichst, Stoff für mehrere Bücher. Ich schlage vor, du informierst dich als erstes ein wenig über zugehörige Patterns: Martin Fowlers Patterns of Enterprise Application Architecture, sollte ein guter Startpunkt sein.

So stehen dir für dein Problem verschiedene Patterns zur Auswahl: Table Data Gateway, Row Data Gateway, Active Record, Data Mapper.

Ich beschäftige mich (wie wohl fast alle hier) auch mit der Entwicklung eines Browsergames, und tendiere bei der eindeutig hohen Komplexität zu den mächtigsten Patterns, in diesem Fall dem Data Mapper.

Somit empfehle ich dir die Logik, die die Datenbankzugriffe verwaltet, aus den Domainobjekten auszulagern, dadurch erhälst du auch mehr Performance, weil du, wenn du es gut machst, pro Objektfamilie nur eine Query brauchst.

gepostet vor 14 Jahre, 5 Monate von knalli

Beim bereits genannten Mappen werde die Objekte/Klassen zu einer Entsprechung im Schema verbunden (mapping). Das ist also bestimmte Menge an Informationen, idR eine Tabelle. Bei deinem "Problem" würde das heißen, das ein Query die Daten liest (25 Felder) und die Abstraktionsschicht der Serviceschicht entsprechend 25 Feld-Objekte (bspw. als Array oder Liste) generiert und zurückgibt. Veränderungen werden am Objekt vorgenommen, eine Speicherung wird/muss wieder durch die Abstraktionsschicht durchgeführt werden.

Aber, das ganze macht man mal nicht so nebenbei und ich empfehle auch hier: Nutze etwas fertiges. Bei ORM kann man soviel falsch machen, das man sich nachher schwarz/gelb ärgert. :p

gepostet vor 14 Jahre, 5 Monate von Phoscur

Ich wusste, dass ich was vergessen hab: Seh dich nach fertigen O/R-Mappern um und probiere ein wenig aus, wie knalli richtig sagt, ist das schreiben eines eigenen Mappers schwierig und meistens verschwendete Zeit.

gepostet vor 14 Jahre, 5 Monate von Phoenix1988

Ich hab mir das Data-Mapper-Pattern jetzt mal angeschaut.

Es ist auf jedenfall schonmal sinnvoll und löst viele meiner Probleme. Mit den restlichen Redundanzen werde ich wohl leben müssen.

Frameworks werde ich wohl nicht benutzen. Mir ist schon klar, dass Frameworks toll sind. Besser als mein Code sein wird. Aber steht bei mir nicht das Produkt, sondern der Entwickler im Vordergrund :)
Deswegen macht es für mich durchaus Sinn einen Mapper selbst zu erstellen, auch wenn ich erstmal keinen richtigen, generischen Mapper erstellen werde.

Wenn es schief geht, werde ich die Sache einfach ausmerke...aussitzen :)

Vielen Dank schonmal für eure Hilfe!

gepostet vor 14 Jahre, 5 Monate von buhrmi

Was du trotzdem auf jeden Fall machen solltest ist dir die Dokumentation zu den ganzen fertigen Frameworks anzuschauen. Zumindest ein Tutorial. Dadurch kommt man meist auch auf gute Ideen für sich selber, auf die man sonst nicht gekommen wär.

gepostet vor 14 Jahre, 5 Monate von DrakeL

Original von Phoenix1988

Frameworks werde ich wohl nicht benutzen. Mir ist schon klar, dass Frameworks toll sind. Besser als mein Code sein wird. Aber steht bei mir nicht das Produkt, sondern der Entwickler im Vordergrund :)

Ich verstehe das Argument nicht, glaubst du du bist ein besserer Entwickler wenn du lieber deinen Kopf durchsetzt und das Rad immer neu erfindest? Ich finde es ist eine wichtige Eigenschaft eines Entwicklers fertige Werkzeug beurteilen und nutzen zu können. Wichtiger als alles selbst machen zu können.

Oder geht es dir nur um den Lerneffekt? Dann mache dir eine Bibliothek die dies leistet, teste diese und nutze danach eine fertige Bibliothek. Ich habe zwei Jahre lang meine Bibliothek geschrieben nur für den Lerneffekt. Mittlerweile habe ich diese eingepackt und nutze Zend Framework.

Ein angepasstes/eigenes Framework beansprucht viel Zeit und Können um erstmal die gleiche Produktivität wie ein fertiges Framework zu erreichen. Für ein 1 Mann Projekt lohnt es sich meiner Meinung nach nicht. Für eine Firma die mehrere Projekte damit umsetzt schon eher.

gepostet vor 14 Jahre, 5 Monate von Murmeli

Da hat DrakeL vollkommen recht. Um zu lernen wie ein Framework funktioniert, sollte man erstmal ein fertiges benutzen und verstehen. Wenn man dies dann verinnerlicht hat, und das Thema weiter vertiefen möchte, kann man immer noch mal was eigenes anfangen.

Wobei ich nicht ganz den sinn darin sehe, ein O/R-Mappern für ein Browserspiel zu verwenden. Denn die Objekte überdauern in der Regel sowieso nur einen Request - außer man packt sich haufenweise Zeug in die Session. Aber das ist genau das, was ich bei einem BG vermeiden würde.

Ich weiß nicht welche Datenbank hier verwendet wird. Aber falls sie das kann, ist es auch sehr praktisch SQL-Batches zu schreiben die mehrere Ergebnismengen zurückliefern. Diese kann man dann zu Objekten zusammenbauen.

P.S. @DrakeL: spielst du zufällig Battleforge? :>

gepostet vor 14 Jahre, 5 Monate von DrakeL

Original von Murmeli

Wobei ich nicht ganz den sinn darin sehe, ein O/R-Mappern für ein Browserspiel zu verwenden. Denn die Objekte überdauern in der Regel sowieso nur einen Request - außer man packt sich haufenweise Zeug in die Session. Aber das ist genau das, was ich bei einem BG vermeiden würde.

Gerade ein Browsergame kann sehr komplex werden, da ist es ratsam Möglichkeiten zu nutzen den Quellcode zu vereinfachen. Ich finde es sehr viel lesbarer und effizienter nicht für jedes kleine SQL schreiben zu müssen sondern objektorientiert auf meine Daten zuzugreifen. Beim Zend Framework zum Beispiel einfach ein assotiatives Array an eine Table Klasse übergeben wenn man einen Insert machen will statt jedesmal ein Insert Statement zu schreiben mit Platzhaltern, Variablen übergeben bzw. selbst alles maskieren usw.

PHP:

//daher
$user = new User();
$user->insert(array('name' => $name, 'email' => $email, ...));
//statt
mysql_query('insert into users (name, email) values ('.mysql_real_escapce_string($name).', '.mysql_real_escapce_string($email).')');

Außerdem kann es die Sicherheit erhöhen, denn gerade die Maskierung ist ja sehr wichtig und wird bei ORM in der Regel im Hintergrund gemacht, daher man kann es nicht vergessen.

P.S. @DrakeL: spielst du zufällig Battleforge? :>

Jep, momentan aber mehr Aion und Eve online. Kannst mir ja ne PM schreiben wenn ma zusammen zocken willst. ^^

gepostet vor 14 Jahre, 5 Monate von Murmeli

Leider hab ich im moment kaum noch Zeit zum Spielen, da ich die wenige Freizeit in die Entwicklung stecke.

Naja, nen O/R-Mapper ist ja auch dafür da, Änderungen an Objekten unkompliziert in die Datenbank zu seralisieren. Da die Objekte aber nur einen Request überdauern in der Regel, lohnt es sich kaum den Aufwand zu betreiben um die Objekte zu erstellen und zu verwalten...

Aber ich würd es trozdem machen, allein um es Wartbar und übersichtlich zu halten :)

Aktuell greife ich auf die Datenbank ausschließlich über Stored Procedures zu. Ich weiß - SP's sind heiß disuktiert. Ich zieh mir die dann aber einfach über LinQ in die Anwendung und muss mich nicht mehr um den Datenzugriff kümmern, da mir LinQ aus den SP's einfache Methodenaufrufe mit generierten Objektlisten als Rückgabe liefert. Das ist vielleicht nicht 100% optimal, aber es erleichtert die Entwicklungsarbeit enorm :)

gepostet vor 14 Jahre, 5 Monate von Santonian

Jap, da kann ich meinem Vorposter nur zustimmen.

Ich nutzte z.B. Hibernate als ORMapper in meinem Projekt. Sobald man sich mal mit dem Framework angefreundet hat ist es um so viel einfacher zu arbeiten.

Vor allem braucht man sich, sofern alles korrekt konfiguriert ist, um nichts mehr zu kümmern was die DB angeht. Zum Anlegen von Daten in der DB gehe ich z.B. so vor:

Java:

User newUser = new User("loginname", "email");
userService.save(user);

 Das Insertstatement wird für mich im Hintergrund generiert und abgesetzt.

Ein Abfragen der DB sieht z.B. so aus:

Java:

User myUser = userService.getByLoginName("loginname");

 Auch hier wird wieder alles im Hintergrund generiert.

Ich muss also nur mit meinen Objekten arbeiten und überlasse Hibernate die ganze Drecksarbeit.

Wenn ich dann allerdings mal selber eingreifen will, also ein SQL Statement selber schreiben,  dann ist kann ich das auch tun.

Es ist so ein wenig wie damals als ich von Strukturierter Programierung auf OOP gewechselt bin. Im ersten Moment fragst du dich, was man mit dem Dreck alle soll und versteht nicht viel. Aber sobald man damit umgehen kann möchte man es nicht mehr missen.

Gruß

Santo.

gepostet vor 14 Jahre, 5 Monate von knalli

Sollte man freundlicherweise noch HQL erwähnen, um auch dem letzten klar zu machen, das ORM nicht nur stupides Mappen auf Klassenebene ist :)

Bspw. HQL = "from User where loginName = ?" => SQL = "SELECT .... FROM tab_users u where u.username = ?" u.v.m. 

gepostet vor 14 Jahre, 5 Monate von buhrmi

Original von Murmeli

Da die Objekte aber nur einen Request überdauern in der Regel, lohnt es sich kaum den Aufwand zu betreiben um die Objekte zu erstellen und zu verwalten...

JEDER hier wird dir 1000 weitere gute Gründe nennen können, warum objektorientiertes Arbeiten sinnvoll ist. Auch wenn sie nicht "mehrere Requests" überdauern.

gepostet vor 14 Jahre, 5 Monate von Murmeli

Original von buhrmi

Original von Murmeli

Da die Objekte aber nur einen Request überdauern in der Regel, lohnt es sich kaum den Aufwand zu betreiben um die Objekte zu erstellen und zu verwalten...

JEDER hier wird dir 1000 weitere gute Gründe nennen können, warum objektorientiertes Arbeiten sinnvoll ist. Auch wenn sie nicht "mehrere Requests" überdauern.

 Nein, versteht mich nicht falsch. Ich hab überhaupt nichts gegen Objektorientierung oder ORM. Aber man muss halt auch abwägen in wie weit sich was genau lohnt.

gepostet vor 14 Jahre, 5 Monate von knalli

Spätestens, wenn man das erste Projekt macht, in welchem man als Entwickler das Schema *nicht* in der Hand hat - im Sinne von Entscheidung, Erstellung und Pflege - , kommt die Überlegung sicherlich von Neuem auf..

gepostet vor 14 Jahre, 5 Monate von Murmeli

Original von knalli

Spätestens, wenn man das erste Projekt macht, in welchem man als Entwickler das Schema *nicht* in der Hand hat - im Sinne von Entscheidung, Erstellung und Pflege - , kommt die Überlegung sicherlich von Neuem auf..

 Hehe, reden wir jetzt von schmutzigem Projektgeschäft oder von selbstentwickelten Browserspielen? ;)

gepostet vor 14 Jahre, 5 Monate von Kampfhoernchen

Das eine kann sich schnell zum anderen Entwickeln. Gameforge hat lange mit dem Sourcen-Müll von ogame gekämpft. Dann haben sies neu geschrieben.

gepostet vor 14 Jahre, 5 Monate von BlackScorp

hm.. ich habe mir alles hier öffters durchgelesen und eigentlich ist es doch ganz schön wenn sowas eintippt:

PHP:

$sql = new mySqlClass();

$sql->insert('tabelle')->values(array('spalte1'=>'wert1','spalte2'=>'wert2'))->where("spalte = 10")->execute();


aber verbraucht das nicht ressourcen wenn eine sql query erstmal zusammengebaut werden muss?

ich meine wenn ich selber eine query per hand eintippe und die ausführe, das wäre doch ressourcensparrender oder?

gepostet vor 14 Jahre, 5 Monate von tector

Natürlich braucht das Ressourcen. Aber die Vorteile überwiegen, so dass der kleine Performanceverlust in Kauf genommen wird. Je größer die Anwendung, desto weniger wirst du an oop/orm herumkommen.

Das ist ähnlich als wenn man sagt "Ich verzichte auf ordentliche Quellcodeeinrückung und Dokumentation aus Performancegründen".

gepostet vor 14 Jahre, 5 Monate von DrakeL

Es gibt ein "where" Original von tector

Natürlich braucht das Ressourcen. Aber die Vorteile überwiegen, so dass der kleine Performanceverlust in Kauf genommen wird. Je größer die Anwendung, desto weniger wirst du an oop/orm herumkommen.

Das ist ähnlich als wenn man sagt "Ich verzichte auf ordentliche Quellcodeeinrückung und Dokumentation aus Performancegründen".

Vor allem sind die Unterschiede recht klein im Vergleich zur Dauer von Datenbankabfragen. Man sollte meiner Meinung nach eine Anwendung so flexible (vor allem wenn sie danach weiterentwickelt wird wie es bei vielen BGs immer der Fall ist) und wartbar wie möglich machen. Sollte die Performance am Ende ein Problem darstellen sucht man die Gründegezielt mit einem Profiler. Und in der Regel liegt der Grund nicht in solch Designfragen sondern in komplexen Schleifenkonstrukten oder ineffiziente Datenbankabfragen.

gepostet vor 14 Jahre, 5 Monate von knalli

Original von BlackScorp

$sql->insert('tabelle')->values(array('spalte1'=>'wert1','spalte2'=>'wert2'))->where("spalte = 10")->execute();


aber verbraucht das nicht ressourcen wenn eine sql query erstmal zusammengebaut werden muss?

ich meine wenn ich selber eine query per hand eintippe und die ausführe, das wäre doch ressourcensparrender oder?

Gut, gerade so einfacher Code braucht in einem Standard-SQL weniger Platz, ist übersichtlicher und lässt sich immernoch beliebig transformieren.

Aber, sehr nahe an Criteria.

gepostet vor 14 Jahre, 5 Monate von Santonian

Original von BlackScorp

aber verbraucht das nicht ressourcen wenn eine sql query erstmal zusammengebaut werden muss?

Also ich behaupte das ist nicht Messbar!

Wer das Gegenteil behauptet muss es mir beweisen. :)

gepostet vor 14 Jahre, 5 Monate von knalli

Natürlich verbraucht das Ressourcen. Jeder Applikationsserver ist so gesehen ein Monster. Kriegt man in der Theorie mit Plaintext wesentlich performanter hin.

gepostet vor 14 Jahre, 5 Monate von BlackScorp

also ist es quasi nur dazu gedacht um programmierern tipp arbeit zu erleichtern und bessere lesbarkeit?

gepostet vor 14 Jahre, 5 Monate von knalli

Ich war drauf und dran, das ganze mit einem ironischen "Ja, klar!" zu beantworten.. um nicht zu abzudriften, verweise ich mal ganz prinzipiell auf das Schichtenmodell, auf die Kapselung und die Kompetenz/Zuständigkeit. Und um ein Beispiel zu nehmen: OSI/ISO-Schichtenmodell. Der Payload (Nutzdaten) ist im Vergleich zum Overload (Steuerungsdaten) eigentlich beschissen.. 

gepostet vor 14 Jahre, 5 Monate von Santonian

Original von knalli

Natürlich verbraucht das Ressourcen. Jeder Applikationsserver ist so gesehen ein Monster. Kriegt man in der Theorie mit Plaintext wesentlich performanter hin.

Das bestreite ich ja auch gar nicht, ich bezog mich nur auf das reine Umwandeln einer, Criteria wegen meiner, in ein SQL Statement gegenüber SQL Statement per Hand eintippen. Das ich, wenn ich z.B. Hibernate einsetze, ein AppServer benötige der evtl. schwerfälliger als ein einfacher WebServer ist, ist klar. Das meinte ich hier aber nicht.

Original von BlackScorp

also ist es quasi nur dazu gedacht um programmierern tipp arbeit zu erleichtern und bessere lesbarkeit?

Auch, aber nicht nur. Mir fallen noch andere Gründe ein, z.B. reduzierung von Fehleranfälligkeit, schutz vor SQL-Injection (bei Benutzung von Named Parameters) und und und...

Die Diskussion ob ein O/R-Mapper sinnvoll ist oder nicht muss aber letztendlich jeder für sich entscheiden in dem er Kosten und Nutzen abwägt. Nicht in jedem Projekt macht es Sinn. Ich würde ohne nicht mehr Arbeiten wollen, aber das zählt halt nur für mich. Für andere Entwickler und andere Projekte mag anderes gelten.

Es schadet zumindest nicht, sich mit dem Thema mal intensiver zu beschäftigen, danach kann man es ja immer noch ablehnen.

Gruß

Santo.

gepostet vor 14 Jahre, 5 Monate von Todi42

Original von DrakeL

Vor allem sind die Unterschiede recht klein im Vergleich zur Dauer von Datenbankabfragen. Man sollte meiner Meinung nach eine Anwendung so flexible (vor allem wenn sie danach weiterentwickelt wird wie es bei vielen BGs immer der Fall ist) und wartbar wie möglich machen. Sollte die Performance am Ende ein Problem darstellen sucht man die Gründegezielt mit einem Profiler. Und in der Regel liegt der Grund nicht in solch Designfragen sondern in komplexen Schleifenkonstrukten oder ineffiziente Datenbankabfragen.

 Ein guten Argument dafür ist immer, dass wenn man die Software so schreibt, dass die Entwicklungszeiten kurz sind, später mehr Zeit für Optimierungen übrig ist ;-)

gepostet vor 14 Jahre, 5 Monate von Phoenix1988

@DrakeL:
Ja, ich glaube tatsächlich das ich ein besserer Entwickler werde, wenn ich einen Mapper selbst schreibe, anstatt ein Framework zu nutzen. Aus dem selben Grund aus dem ich auch schon Heapsort und Co. gelernt und einmal durchentwickelt habe. Für manche kommt der Strom halt nicht aus der Steckdose...

Irgendwie ist der Entwicklerbereich nicht die wirklich große Bereicherung...
Kenntnisse der Feedback-Regeln wären hielfreich...und nicht immer die leidige OOP-Diskussion, die langsam schon religiöse Züge anzunehmen scheint.

gepostet vor 14 Jahre, 5 Monate von DrakeL

Original von Phoenix1988

@DrakeL:
Ja, ich glaube tatsächlich das ich ein besserer Entwickler werde, wenn ich einen Mapper selbst schreibe, anstatt ein Framework zu nutzen. Aus dem selben Grund aus dem ich auch schon Heapsort und Co. gelernt und einmal durchentwickelt habe. Für manche kommt der Strom halt nicht aus der Steckdose...

Wenn es um den Lerneffekt geht keine Frage, da würde ich es auch jedem empfehlen der Lust und Zeit hat.

Wenn es um den reinen Einsatz geht halte ich Leute die sich in fertige Tools einarbeiten und nutzen können (wenn diese die Anforderungen erfüllt) für Kompetenter als Leute die immer alles selbst machen müssen und so in einem Projekt unnötig Zeit verbrauchen. Was bringt einem der beste Entwickler, wenn er 3 Monate für ein Framework benötigt was am Ende genau das gleiche abdeckt was Framework XY schon längst kann und bewiesen hat.

Natürlich sollte auch ein Entwickler der fertige Tools nutzt in der Lage sein eigene Erweiterungen einzubringen um abweichende Anforderungen umzusetzen oder alles fehlende noch zu implementieren, keine Frage.

gepostet vor 14 Jahre, 4 Monate von phi

thema OOP und Datenbanken: mysqli lässt sich auch objektorientiert verwenden... wobei mir der sinn noch nicht aufgegangen ist.

gepostet vor 14 Jahre, 4 Monate von TheUndeadable

wobei mir der sinn noch nicht aufgegangen ist.

Das Handle in den MySQL-Funktionen ist dir schon aufgefallen?

http://de.php.net/manual/en/mysql.resources.php

Genau das wird in mysqli mehr oder weniger gekapselt. => Angenehmere Programmierung, da ein Datenbankverbindungsobjekt angenehmer ist als Funktionen, die ein solches Handle zur Adressierung nutzen.

BTW: Dies hat nichts mit der OOP-Problematik hier im Thread zu tun.

Auf diese Diskussion antworten