Michilee: Loginobjekt mit Hibernate

Hallo Forum,

ich will mich am WE an ein Loginbereich ranmachen.

Kann kurz:
User schickt Name und PW an eine auth.jsp. Dort wird PW und Name mit DB abgeglichen, sobald es in Ordnung ist, wird ein Userobjekt mit ein paar Daten (alter, name, wohnort, geschlecht...) erzeugt und in die aktuelle session(ID) gespeichert.

Bei jedem request wird dann überprüft, ob in der session ein userobjekt enthalten ist. falls ja, ist user noch eingeloggt. in dem objekt sind ja schon ein paar wichtige daten wie geschlecht usw. enthalten. falls mehr notwendig sein sollte, wird von DB kurzfristig, bzw. temporär nachgeladen.

Hatte aber mal ein Tipp erhalten, das irgendwie mit Hibernate zu machen:

[i]Man würde also für jeden Request das Benutzer-Objekt aus der Session laden, sich eine DB-Verbindung aus dem Pool holen und eine Transaktion
starten, das Objekt wieder an die Transaktion binden (das muss man explizit tun, wenn man Datenobjekte über mehrere Transaktionen hinweg
verwendet.)
Anschließend kann man mit dem Objekt weiterarbeiten, ohne sich um irgend etwas zu kümmern.[/i]

was meint man mit transaktion binden?

da muss ich mich richtig gut mal in hibernate wohl einarbeiten.

meine wichtigere frage jedoch, was ich auch gelesen hatte, vor allem weil ich ja auch objekte in die session speichere:

[i]Session-Objekt muss sersialisierbar sein, Objekte sind es aber normalerweise nicht. [/i]

wie ist das zu verstehen?

grüße

  1. Guten Morgen!

    [...] User schickt Name und PW an eine auth.jsp. Dort wird PW und Name mit DB abgeglichen, sobald es in Ordnung ist, wird ein Userobjekt mit ein paar Daten (alter, name, wohnort, geschlecht...) erzeugt und in die aktuelle session(ID) gespeichert.

    Arbeitest Du hier ausschließlich mit JSPs? Wenn ja, dann solltest Du Dich vor der Verwendung von Hibernate erst noch kurz in Model2 bzw. MVC für Java Webanwendungen einlesen und Deine Anwendung entsprechend umstellen. Kurz gesagt geht es dabei darum, dass eine JSP ausschließlich die View einer Anwendung ist, für die Clientlogik wird ein Servlet verwendet. Das Servlet sollte dann nicht direkt mit Hibernate arbeiten, sondern den Zugriff auf die Geschäftslogik über eine Serviceklasse abkapseln. Das ist auch wichtig für die Transaktionssteuerung und die korrekte Einhaltung von Transaktionsgrenzen (s.u.).

    [...]
    [i]Man würde also für jeden Request das Benutzer-Objekt aus der Session laden, sich eine DB-Verbindung aus dem Pool holen und eine Transaktion
    starten, das Objekt wieder an die Transaktion binden (das muss man explizit tun, wenn man Datenobjekte über mehrere Transaktionen hinweg
    verwendet.)
    Anschließend kann man mit dem Objekt weiterarbeiten, ohne sich um irgend etwas zu kümmern.[/i]

    Ja, das ist so ungefähr richtig, ohne wirkliche Einarbeitung in das Thema Hibernate wird es aber vermutlich trotzdem noch sehr schwierig für Dich. Hibernate mappt automatisch Attribute von Klassen auf Attribute eines Datensatzes in der Datenbank. Wenn Du also von Hibernate ein Objekt aus der Datenbank ermitteln lässt, dann führt Hibernate den Select aus, ermittelt die Attribute einer oder mehrerer Relationen und legt sie in einem Objekt(graphen) ab. So lange Du Dich mit diesem Objekt in einer Hibernate Session (Achtung, hier passiert es gerne, dass man das mit der Servlet Session verwechselt) befindest, kannst Du das Objekt manipulieren und beim Verlassen der Session (Transaktionsende) werden die geänderten Attribute in der Datenbank aktualisiert.
    Wenn Du jetzt aber mit Deinem Objekt die Hibernate Session verlässt (weil Du das Objekt aus dem Service an das Servlet übergibst), dann ist das Objekt "detached" und wird verwendet wir ein normales POJO sonst auch. Wenn es jetzt aber vom Benutzer geändert wird (über ein Formular, Du lädst das Objekt aus der Session, gibst ihm neue Eigenschaften und sendest es an den Service), dann muss es erst "reattached" werden, damit Hibernate wieder eine Verbindung vom Objekt zur Datenbank hat und die Attribute entsprechend aktualisieren kann (in der DB).

    was meint man mit transaktion binden?

    Hier ist das Reattachment gemeint. Hibernate arbeitet natürlich immer in einer Transaktion, die man deklarativ (z.B. über Spring) oder programmatisch (z.B. JTA API) steuern kann. Hierzu solltest Du die Hibernate Doku zu Rate ziehen, das führt hier zu weit: http://docs.jboss.org/hibernate/stable/core/reference/en/html/

    da muss ich mich richtig gut mal in hibernate wohl einarbeiten.

    Ja, das wäre passend. :)

    [...]
    [i]Session-Objekt muss sersialisierbar sein, Objekte sind es aber normalerweise nicht. [/i]

    Das ist eigentlich die einfachste Frage an Deinem Vorgehen. ;)
    Damit ein Objekt über Systemgrenzen hinweg verschickt werden kann, muss es serialisierbar sein (also in einen Bytestrom reversibel transferierbar). Das passiert in Java über das Marker-Interface java.io.Serializable. Wenn eine Klasse dieses Interface implementiert, dann wird damit versichert, dass alle Attribute serialisiert werden können (also primitive Datentypen sind oder selbst serialisierbare Objekte). Das sollte bei Hibernate POJOs immer der Fall sein, weil die ja gerne mal über verschiedene Maschinen hinweg transportiert werden.
    Noch ein Hinweis, weil das früher oder später wichtig für Dich wird: Lese Dich (sofern noch nicht passiert) in die Bedeutung der Methoden equals und hashCode ein. Diese sind zwar nicht nur für Hibernate wesentlich, aber viele Java-Entwickler können trotzdem nicht damit umgehen. Es gibt auch in der Hibernate Doku ein spannendes Kapitel dazu.

    Viel Erfolg bei der Verwendung von Hibernate und lass Dich nicht abschrecken. Wenn man die Konzepte mal verinnerlicht hat, ist es ein wahnsinnig gutes Werkzeug.

    Peter

    1. hi pgoetz,
      vielen dank für die Antwort. Hast alles schön detailiert erklärt.

      Arbeitest Du hier ausschließlich mit JSPs? Wenn ja, dann solltest Du Dich vor der Verwendung von Hibernate erst noch kurz in Model2 bzw. MVC für Java Webanwendungen einlesen und Deine Anwendung entsprechend umstellen. Kurz gesagt geht es dabei darum, dass eine JSP ausschließlich die View einer Anwendung ist, für die Clientlogik wird ein Servlet verwendet. Das Servlet sollte dann nicht direkt mit Hibernate arbeiten, sondern den Zugriff auf die Geschäftslogik über eine Serviceklasse abkapseln. Das ist auch wichtig für die Transaktionssteuerung und die korrekte Einhaltung von Transaktionsgrenzen (s.u.).

      ja, ich hatte schon mal gelesen, dass man Ausgabe für Browser, Logik usw. trennen sollte. Bisher habe ich viel in JSP's geregelt gehabt und paar Sachen in servlets ausgelagert. Ging auch ganz schön, wenn ich von JSP aus Daten dann in sevlet weitergeleitet/übergeben hatte und dann wieder zurück. Die JSP selbet hatte manchmal auch selber Java-code gehabt. Zum Beispiel Usereingaben prüfen oder je nach Parameter im Request oder Eingabe dann ein ein anderes Design/Html-Code Ausgabe usw.

      Trennung zwischen Design-Ausgabe und Logik usw. wäre natürlich gut. Ich frag mich aber, ob man das überhaupt schön trennen kann, da man manchmal je nach Request verschiedene HTML-Codes auch hat, oder Text. Innerhalb von Texten hat man manchmal Formatierungen usw.

      Aber, ich schau mir mal das MVC mal an, vielleicht finde ich ja gute Musterbeispiele.

      Wenn Du jetzt aber mit Deinem Objekt die Hibernate Session verlässt (weil Du das Objekt aus dem Service an das Servlet übergibst), dann ist das Objekt "detached" und wird verwendet wir ein normales POJO sonst auch. Wenn es jetzt aber vom Benutzer geändert wird (über ein Formular, Du lädst das Objekt aus der Session, gibst ihm neue Eigenschaften und sendest es an den Service), dann muss es erst "reattached" werden, damit Hibernate wieder eine Verbindung vom Objekt zur Datenbank hat und die Attribute entsprechend aktualisieren kann (in der DB).

      ach so. ok, ich lese mich mal in Hibernate ein. Dann ist da wohl vorsicht geboten, wenn ich mit Hibernate von der DB ein Objekt mappe und mit dem gemappten Objekt weiterarbeite. (Um die Hibernate-Session nicht zu verlassen, sollte ich dann das Objekt nicht an das Servlet übergeben.... Das gemappte Ergebnis kommt doch aber wahrscheinlich in das Servlet rein? Wie gesagt, bevor ich dumme Fragen stelle, lese ich miche rst einmal ein :-) )

      Das ist eigentlich die einfachste Frage an Deinem Vorgehen. ;)
      Damit ein Objekt über Systemgrenzen hinweg verschickt werden kann, muss es serialisierbar sein (also in einen Bytestrom reversibel transferierbar). Das passiert in Java über das Marker-Interface java.io.Serializable. Wenn eine Klasse dieses Interface implementiert, dann wird damit versichert, dass alle Attribute serialisiert werden können (also primitive Datentypen sind oder selbst serialisierbare Objekte). Das sollte bei Hibernate POJOs immer der Fall sein, weil die ja gerne mal über verschiedene Maschinen hinweg transportiert werden.

      Optimal. Ich schau mir Intefaces dann auch nochmal an. (Wenn man ein Interface addiert, war es ja so ähnlich wie eine Vererbung. Mit abstract wird man ja gezwungen manche Methode zu implemetieren und manchmal kann man auch Methoden erben oder auch Objektvariablen nutzen. Hoffentlich habe ich das noch richtig in Erinnerung

      Noch ein Hinweis, weil das früher oder später wichtig für Dich wird: Lese Dich (sofern noch nicht passiert) in die Bedeutung der Methoden equals und hashCode ein. Diese sind zwar nicht nur für Hibernate wesentlich, aber viele Java-Entwickler können trotzdem nicht damit umgehen. Es gibt auch in der Hibernate Doku ein spannendes Kapitel dazu.

      hashCode sagt mir jetzt nichts. Mit equals schaut man ja, ob die Referenz/Zeiger des Objekts gleich ist.

      Grüße

      1. Guten Morgen!

        [...]
        ja, ich hatte schon mal gelesen, dass man Ausgabe für Browser, Logik usw. trennen sollte. Bisher habe ich viel in JSP's geregelt gehabt und paar Sachen in servlets ausgelagert. Ging auch ganz schön, wenn ich von JSP aus Daten dann in sevlet weitergeleitet/übergeben hatte und dann wieder zurück. Die JSP selbet hatte manchmal auch selber Java-code gehabt. Zum Beispiel Usereingaben prüfen oder je nach Parameter im Request oder Eingabe dann ein ein anderes Design/Html-Code Ausgabe usw.
        Trennung zwischen Design-Ausgabe und Logik usw. wäre natürlich gut. Ich frag mich aber, ob man das überhaupt schön trennen kann, da man manchmal je nach Request verschiedene HTML-Codes auch hat, oder Text. Innerhalb von Texten hat man manchmal Formatierungen usw.

        Ja, das geht schon gut. Trennung von Logik und Repräsentation heißt ja nicht, dass man in einer JSP nicht anhand eines Zustands entweder die eine, oder eine andere Meldung ausgeben darf (z.B. Erfolgs- und Fehlermeldung). Die Grenze sind bei mir Scriptlets. In meinen Projekten dulde ich keine Scriptbereiche in JSPs. Wenn es Logik gibt, die innerhalb der View verwendet werden muss (z.B. zusammensetzen eines Links), dann wird das in ein Tag ausgelagert. Ansonsten reicht die JSTL mit den Standardtags (z.B. c:if, c:forEach, fmt:formatDate, ...). Ich arbeite jetzt seit einigen Jahren fast ausschließlich in Java Webprojekten und habe noch in keinem Projekt ein Scriptlet benötigt. Und alle Daten, die in der View benötigt werden, können im Servlet ermittelt und passend aufbereitet werden.

        [...]
        ach so. ok, ich lese mich mal in Hibernate ein. Dann ist da wohl vorsicht geboten, wenn ich mit Hibernate von der DB ein Objekt mappe und mit dem gemappten Objekt weiterarbeite. (Um die Hibernate-Session nicht zu verlassen, sollte ich dann das Objekt nicht an das Servlet übergeben.... Das gemappte Ergebnis kommt doch aber wahrscheinlich in das Servlet rein? Wie gesagt, bevor ich dumme Fragen stelle, lese ich miche rst einmal ein :-) )

        Man kann das Objekt schon an das Servlet übergeben, aber es sollte vorher detached werden, also von der Hibernate Session abgekoppelt. Hier sollte man alle Daten mitnehmen, die man in der View benötigt (Stichwort lazy loading), da man ansonsten im Client beim Zugriff auf untergeordnete Objekte im Objektgraphen eine LazyLoadingException einfängt. Aber das ist dann schon die fortgeschrittenere Thematik.

        Optimal. Ich schau mir Intefaces dann auch nochmal an. (Wenn man ein Interface addiert, war es ja so ähnlich wie eine Vererbung. Mit abstract wird man ja gezwungen manche Methode zu implemetieren und manchmal kann man auch Methoden erben oder auch Objektvariablen nutzen. Hoffentlich habe ich das noch richtig in Erinnerung

        Ja, fast. Abstrakte Klassen werden nicht gezwungen, Methoden zu implementieren. Nicht-abstrakte Klassen müssen alle Methoden ihrer Interfaces implementieren. Abstrakte Klassen dürfen Methoden implementieren, können aber bestimmte Methoden abstrakt (nicht implementiert) weitervererben. Beim Interface Serializable ist das allerdings kein Problem, weil es ein reines Marker-Interface ist und keine Methoden definiert, die implementiert werden müssten. Es zeigt nur an, dass das Objekt serialisierbar ist.

        [...]
        hashCode sagt mir jetzt nichts. Mit equals schaut man ja, ob die Referenz/Zeiger des Objekts gleich ist.

        equals existiert ohne hashCode nicht. Die beiden Methoden hängen eng zusammen, deshalb solltest Du Dich mit denen ruhig ein wenig intensiver beschäftigen. Wenn man sich nur um eine Methode kümmert oder nicht um beide gleichzeitig, können die ekelhaftesten Fehler entstehen, die man ewig sucht.

        Schöne Grüße,

        Peter

        1. nabend,

          Ja, das geht schon gut. Trennung von Logik und Repräsentation heißt ja nicht, dass man in einer JSP nicht anhand eines Zustands entweder die eine, oder eine andere Meldung ausgeben darf (z.B. Erfolgs- und Fehlermeldung). Die Grenze sind bei mir Scriptlets. In meinen Projekten dulde ich keine Scriptbereiche in JSPs. Wenn es Logik gibt, die innerhalb der View verwendet werden muss (z.B. zusammensetzen eines Links), dann wird das in ein Tag ausgelagert. Ansonsten reicht die JSTL mit den Standardtags (z.B. c:if, c:forEach, fmt:formatDate, ...). Ich arbeite jetzt seit einigen Jahren fast ausschließlich in Java Webprojekten und habe noch in keinem Projekt ein Scriptlet benötigt. Und alle Daten, die in der View benötigt werden, können im Servlet ermittelt und passend aufbereitet werden.

          wenn du alles in deinen servlets regelst,dann leitest womöglich den ganzen request via bean direkt in die servlet ne?

          1. nabend,

            Guten Morgen!

            [...]
            wenn du alles in deinen servlets regelst,dann leitest womöglich den ganzen request via bean direkt in die servlet ne?

            Das verstehe ich jetzt nicht. Den Request muss ich nicht in einer Bean verschicken, der geht direkt über den Servlet-Container an das Servlet. Das Prozedere sieht in etwa so aus:
            Benutzer -> http://www.example.com/app/servlet -> com.example.app.servlets.Servlet -> RequestDispatcher -> JSP

            Der Benutzer gibt also eine Adresse ein, deren Pfad ich auf ein bestimmtes Servlet gemapped habe. Das Servlet tut mit dem Request, was es tun soll (Daten lesen, speichern, manipulieren, als Attribut in den Request legen) und gibt die Kontrolle über den RequestDispatcher an eine JSP weiter. In der JSP wird dann zur Anzeige der Daten auf die Attribute des Requests zugegriffen.
            Ich hoffe, das macht es ein wenig klarer.

            Schöne Grüße,

            Peter

            1. Hi Peter,
              vielen vielen Dank, dass du dir bei den Antworten so Mühe machst.

              [...]
              wenn du alles in deinen servlets regelst,dann leitest womöglich den ganzen request via bean direkt in die servlet ne?

              Das verstehe ich jetzt nicht. Den Request muss ich nicht in einer Bean verschicken, der geht direkt über den Servlet-Container an das Servlet. Das Prozedere sieht in etwa so aus:
              Benutzer -> http://www.example.com/app/servlet -> com.example.app.servlets.Servlet -> RequestDispatcher -> JSP

              Ah, ok, du sprichst direkt per URL die servlet an, bzw. mappst drauf.

              Der Benutzer gibt also eine Adresse ein, deren Pfad ich auf ein bestimmtes Servlet gemapped habe. Das Servlet tut mit dem Request, was es tun soll (Daten lesen, speichern, manipulieren, als Attribut in den Request legen) und gibt die Kontrolle über den RequestDispatcher an eine JSP weiter. In der JSP wird dann zur Anzeige der Daten auf die Attribute des Requests zugegriffen.
              Ich hoffe, das macht es ein wenig klarer.

              genau. in der servlet verarbeitest du alles (daten, benutzereingaben, db-abfragen uvm..) und erzeugst praktisch eine ausgabe (nur daten ohne html), die du an eine "vorhandene" jsp schickst, bzw. eine jsp fütterst?

              in den jsp hast du dann praktisch keine links, die auf jsp's zeigt, sondern direkt auch servlets. ja, so hört sich alles schon viel viel verständlicher an.

              ich hatte da am anfang etwas komplizierter gedacht, indem die jsp die daten erst an die servlet schicken muss und danach wieder zurück.

              Peter

              1. Servus,

                [...]
                Ah, ok, du sprichst direkt per URL die servlet an, bzw. mappst drauf.

                Exakt, alle Links innerhalb der Anwendung gehen immer über ein Servlet (manchmal ein reines Dispatcher-Servlet (leitet nur auf eine JSP weiter, ohne etwas zu tun), wenn keine Daten zu verarbeiten sind (z.B. Anzeige einer Kontaktseite)). Nach außen werden die Adressen der JSPs nicht sichtbar. Ich speichere meine JSPs sogar immer unterhalb von WEB-INF/, damit keiner im Team aus Versehen mal eines direkt referenziert.

                [...]
                ich hatte da am anfang etwas komplizierter gedacht, indem die jsp die daten erst an die servlet schicken muss und danach wieder zurück.

                An die Denkweise bei Model2 muss man sich erst gewöhnen, vor Allem, wenn man einer Sprache wie z.B. PHP kommt und dort skriptbasiert gearbeitet hat. Wenn man es aber mal verinnerlicht hat, dann ist es eine sehr elegante Art, Webanwendungen zu schreiben.

                Viel Erfolg!

                Peter

                1. servus,

                  An die Denkweise bei Model2 muss man sich erst gewöhnen, vor Allem, wenn man einer Sprache wie z.B. PHP kommt und dort skriptbasiert gearbeitet hat. Wenn man es aber mal verinnerlicht hat, dann ist es eine sehr elegante Art, Webanwendungen zu schreiben.

                  hey peter danke, hat mir alles echt sehr sehr geholfen. ich mache mich mal demnächst an ein kleines projekt. sollte ich neue fragen haben, poste ich einfach einen neuen thread rein. ich hoffe, dass ich aber mithilfe von google, falls fragen auftauchen sollten ohne große hindernisse vorankomme

                  grüße und ein schönes wochenende noch
                  michi