MichiLee: Seriazible

Hallo Forum,
ich tauche leider wieder mit ein paar Fragen auf.
Ich muss leider das Thema Seriazible aufgreifen. Ich habe zwar in der JavaInsel gelesen, verstehe es aber dennoch nicht ganz:

Es taucht dieses Beispiel auf:

FileOutputStream fs = new FileOutputStream"data1.dat");  
ObjectOutputStream os = new ObjectOutputStream(fs);  
os.writeObject(datalist());  
os.close();
  
try {  
 BufferedWriter bw = new BufferedWriter(new FileWriter("datalist.txt"));  
 String temp = new String("");  
 System.out.println("export data to file..");  
  
 for(int i = 0; i < getDatenliste().size(); i++) {  
  temp = (getDatenliste().get(i)+"\n");  
  bw.write(temp);  
 }  
  
 bw.close();  
 System.out.println("data written to " + datei);  
  
} catch (IOException e) {  
  // TODO Auto-generated catch block  
  e.printStackTrace();  
}

Der FileOutputStream erzeugt und speichert ja einfach die datalist in eine Textdatei, bzw. in data1.dat, welches man dann später wieder auslesen könnte und davor eine Arraylist erzeugen.

Unten beim exportieren muss man dann wie es ausschaut manuell etwas einzeln auslesen und in eine Textdatei speichern/exportieren.

Was ich oben jedoch, bzw. allgemein nicht ganz Verstehe, wenn ich eine Klasse Person mit Attributen String nam, int altr, Kinder knd hätte. (Kinder=Unterklasse, oder Vector<Kinder> knd) Was genau bringt mir, wenn ich in der Klasse noch "Seriazible" implementiere? Seriazible schreibt ja keine Methode vor.

Sage ich dann mit Seriazible nur, dass man mit Setter und Gettern auf all meine Attribute zugreifen kann und somit die Attribute später problemlos exportieren? Irgendwas muss ja hier Geschehen?

Grüße

P.S. Noch ein kleiner Nachtrag gleich in diesem Thread. Ich hatte damals einen Thread bzgl. MVC-Patterns gestartet gehabt bzgl. eines Projektes für unser Studium.
Ich hatte das so gelöst, dass der Controller verschiedene Models aufruft. Das Model bastelt sich dann eine Query zusammen. Führt aber manchmal 2-3 Querys aus.
Sobald ein Model eine Query absetzt und den Abtraktionslayer aufruft, wird praktisch 2-3 eine Datenbankverbindung auf- und wieder abgebaut. Ich habe nun erfahren, dass Datenbankconnectionpools Sinn machen würden.

Wie ich aber von meinen Kommilionen gesehen hatte, dass sie Ihre Projekte so gelöst hatten, dass manche eine statische Klasse hatten, um eine Datenbankverbindung aufzubauen. Manche hatten es so gelöst, dass bei einem Login eine Datenbankverbindung aufgebaut wird und erst beim Login wieder abgebaut. Das letztere hört sich nichtmal so schlecht an, wäre das aber dennoch humbuk?

  1. Hallo,

    Sage ich dann mit Seriazible nur, dass man mit Setter und Gettern auf all meine Attribute zugreifen kann und somit die Attribute später problemlos exportieren? Irgendwas muss ja hier Geschehen?

    Vergleiche die Java-Doku:

    [...]
    The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.
    [...]

    Du kennzeichnest damit nur ein serialisierbares Objekt. Wie dieses serialisiert wird, bliebt Dir überlassen (Du kannst z.b. eigene Methoden für writeObject und readObject definieren).

    Nicht immer ist es sinnvoll, eine Klasse serialisierbar zu gestalten
    (Denke an sowas wie eine offene Datenbankverbindung - die kannst Du ja nicht einfach in eine Textdatei packen), deswegen sind nicht alle Objekte "automatisch" serialisierbar, sondern müssen als solche gekennzeichnet werden.

    Wie ich aber von meinen Kommilionen gesehen hatte, dass sie Ihre Projekte so gelöst hatten, dass manche eine statische Klasse hatten, um eine Datenbankverbindung aufzubauen. Manche hatten es so gelöst, dass bei einem Login eine Datenbankverbindung aufgebaut wird und erst beim Login wieder abgebaut.

    Generell ist es schon sinnvoll, die Datenbankverbindung statisch zu machen (in einem Singleton o.ä.) und dann diese offen zu halten, statt für jeden Request immer eine neue Verbindung zu öffnet. Damit spart man sich den Overhead für den Verbindungsaufbau.
    Allerdings bekommt man, wenn man nur eine Verbindung vorsieht, ggf. Probleme, wenn sehr viele Requests abgearbeitet werden müssen - dann laufen diese alle über diese einzige Datenbankverbindung, was ggf. zu Performance-Problemen führt, weil die Requests dann immer warten müssen, bis die DB-verbindung wieder frei ist.

    Daher auch die von Dir angesprochene Connection-Pool-Idee: Eine Zahl von Datenbankverbindungen wird (statisch) aufgebaut und dann offen gehalten.
    Durch dieses Konzept gibt es keinen Overhead für den Verbindungsaufbau, trotzdem kann eine gewisse Anzahl von Connections parallel genutzt werden, und ein Request muss nicht so lange auf das Frei-Werden der Verbindung warten.

    1. Hi mrjerk,

      vielen Dank für die Antwort.

      Du kennzeichnest damit nur ein serialisierbares Objekt. Wie dieses serialisiert wird, bliebt Dir überlassen (Du kannst z.b. eigene Methoden für writeObject und readObject definieren).

      Nicht immer ist es sinnvoll, eine Klasse serialisierbar zu gestalten
      (Denke an sowas wie eine offene Datenbankverbindung - die kannst Du ja nicht einfach in eine Textdatei packen), deswegen sind nicht alle Objekte "automatisch" serialisierbar, sondern müssen als solche gekennzeichnet werden.

      Achso, ja das Objekt für die offene Datenbank kann man nicht einfach so in eine Textdatei schreiben.
      Seriazible sagt dann einfach kurz, dass ich den Zustand den Objekts (egal in was für einer Form auch immer) irgendwo speichern und später wieder auslesen/erstellen kann. Passt meine Aussage?
      (Wie etwas genau zu serialisieren ist, legt dann der oder die Schnittstelle fest, die mit dem Objekt arbeitet?)

      Generell ist es schon sinnvoll, die Datenbankverbindung statisch zu machen (in einem Singleton o.ä.) und dann diese offen zu halten, statt für jeden Request immer eine neue Verbindung zu öffnet. Damit spart man sich den Overhead für den Verbindungsaufbau.
      Allerdings bekommt man, wenn man nur eine Verbindung vorsieht, ggf. Probleme, wenn sehr viele Requests abgearbeitet werden müssen - dann laufen diese alle über diese einzige Datenbankverbindung, was ggf. zu Performance-Problemen führt, weil die Requests dann immer warten müssen, bis die DB-verbindung wieder frei ist.

      Daher auch die von Dir angesprochene Connection-Pool-Idee: Eine Zahl von Datenbankverbindungen wird (statisch) aufgebaut und dann offen gehalten.
      Durch dieses Konzept gibt es keinen Overhead für den Verbindungsaufbau, trotzdem kann eine gewisse Anzahl von Connections parallel genutzt werden, und ein Request muss nicht so lange auf das Frei-Werden der Verbindung warten.

      Ja, das Connection Pool hört sich auf jeden Fall interessant an. Da muss ich mich demnächst gut einlesen. Wir hatten jedoch auch Leute, die für jeden einzelnen Nutzer explizit eine eigene Verbindung (also nicht-statisch) geöffnet haben und bis zum Logout/Schließen des Programms die Verbindung offen gelassen haben. Im Webbereich hatten manche die DB-Verbindung in eine Session gespeichert)

      Bei meinem Programm hat mir nur das nicht gefallen, dass pro Klick/Aktion eines Nutzers manchmal mehrere Querys abgesetzt wurden. Da muss ich mir etwas einfallen lassen, dass es sehr wenig Querys bleiben. Ist halt schwierig, wenn man allgemeine Querys hat, die man für die Ansicht benötigt und dann gleichzeitig noch speziell Daten eines eingeloggten Nutzers)

      Ein kleines Webbeispiel:
      1. Ein Query für Anzahl eingeloggter User und sonstiger Daten (Nicht Userbezogen)
      2. Auf der gleichen Seite, wenn man sich einloggt, zusätzlich eine Query für die eigenen Daten
      3. Wenn man nun auf einer Seite ist, wo man eine Topliste/Gästebuch anzeigt, wäre das wieder eine Query. Also 3 Querys auf einmal.

      Grüße

      1. Hallo,

        Seriazible sagt dann einfach kurz, dass ich den Zustand den Objekts (egal in was für einer Form auch immer) irgendwo speichern und später wieder auslesen/erstellen kann. Passt meine Aussage?

        Ja, das triffts. Wobei Du natürlich die Objekte nicht zwingend speichern musst - Serialisierung kommt z.b. auch beim Übertragen von Objekten zum Tragen (Du könntest z.b. ein serialisiertes Java-Objekt per HTTP oder welchem Protokoll auch immer an einen anderen Host schicken, der es dann wieder auspacken und benutzen kann).

        (Wie etwas genau zu serialisieren ist, legt dann der oder die Schnittstelle fest, die mit dem Objekt arbeitet?)

        Genau. Standardmässig kann erstmal jedes Objekt serialisiert werden, sobald es das Serializable Interface implementiert (nicht immer ergibt das Sinn, vgl. Datenbankverbindung, aber prinzipiell geht es).
        Nur wenn Du die Standard-Serialisierung von Java aus irgend einem Grund anders haben willst, kannst Du in Deiner Klasse die Methoden "readObject" und "writeObject" überladen, und damit das Serialisieren so machen, wie Du es willst.

        Bei meinem Programm hat mir nur das nicht gefallen, dass pro Klick/Aktion eines Nutzers manchmal mehrere Querys abgesetzt wurden. Da muss ich mir etwas einfallen lassen, dass es sehr wenig Querys bleiben. Ist halt schwierig, wenn man allgemeine Querys hat, die man für die Ansicht benötigt und dann gleichzeitig noch speziell Daten eines eingeloggten Nutzers)

        Ich glaube, das Problem auf dass Du da stösst, ist ein "Klassiker":
        Der Object-relational impedance mismatch.
        Vielleicht schonmal gehört? (Vielleicht geh ich jetzt zu sehr in die Tiefe, also lies einfach drüber weg, wenns Dich nicht interessiert ;) ):

        Das Problem ist, dass sich Objektorientierung und relationale Datenbanken eigentlich nicht wirklich gut vertragen:

        Nehmen wir an, Du hast eine Tabelle LOGGED_USERS, die alle eingeloggten User speichert und eine Tabelle USER_DETAILS, die zu jedem Benutzer die Details beinhaltet. Du hast eine Methode "getLoggedInUsers" die die LOGGED_USERS-Tabelle ausliest und daraus eine Liste aus "User"-Objekten erzeugt, und eine Methode "fetchUserDetails()", welche das User-Objekt mit den User-Details befüllt.
        Jetzt möchtest Du (schön objektorientiert) eine Liste aller eingeloggten User mit ein paar Daten aus der Details-Tabelle (vielleicht Vor- und Nachname) anzeigen:

        Iterator<User> users = UserListController.getLoggedInUsers().iterator();

        while (users.hasNext()) {
           User user = users.next();
           user.fetchUserDetails();
           System.out.println(user.getVorname()+" "+user.getNachname());
        }

        Ja doof. Jetzt wird in der Schleife für JEDEN Benutzer ein DB-Request gemacht.
        Also die User-Details-Tabelle vielleicht lieber in der getLoggedInUsers()-Methode auslesen, in dem man sie mit der LOGGED_USERS-tabelle joint (und sich dann die fetchUserDetails-Methode sparen)?
        Könnte man machen, aber was, wenn man dann die Details gar nicht braucht, dann hätte man umsonst Performance für einen JOIN verbraten....

        => Wie mans macht ists Mist. "Object Relational Impedance mismatch" eben :)

        Große Systeme benutzen deswegen Objekt-relationale-Mapper, welche sich darum kümmern, DB-Objekte möglichst performant und geschickt aus der Datenbank zu holen und sie zu cachen, damit die Datenbank-Aufrufe auf ein Minimum beschränkt bleiben.
        Für Java erledigt das z.b. Hibernate.

        Viele Grüße,

        Jörg

        1. Hi mrjerk,

          nochmals vielen vielen Dank für die sehr nette und ausführliche Antwort.

          Das Problem ist, dass sich Objektorientierung und relationale Datenbanken eigentlich nicht wirklich gut vertragen:

          Nehmen wir an, Du hast eine Tabelle LOGGED_USERS, die alle eingeloggten User speichert und eine Tabelle USER_DETAILS, die zu jedem Benutzer die Details beinhaltet. Du hast eine Methode "getLoggedInUsers" die die LOGGED_USERS-Tabelle ausliest und daraus eine Liste aus "User"-Objekten erzeugt, und eine Methode "fetchUserDetails()", welche das User-Objekt mit den User-Details befüllt.
          Jetzt möchtest Du (schön objektorientiert) eine Liste aller eingeloggten User mit ein paar Daten aus der Details-Tabelle (vielleicht Vor- und Nachname) anzeigen:

          Iterator<User> users = UserListController.getLoggedInUsers().iterator();

          while (users.hasNext()) {
             User user = users.next();
             user.fetchUserDetails();
             System.out.println(user.getVorname()+" "+user.getNachname());
          }

          Ja doof. Jetzt wird in der Schleife für JEDEN Benutzer ein DB-Request gemacht.
          Also die User-Details-Tabelle vielleicht lieber in der getLoggedInUsers()-Methode auslesen, in dem man sie mit der LOGGED_USERS-tabelle joint (und sich dann die fetchUserDetails-Methode sparen)?
          Könnte man machen, aber was, wenn man dann die Details gar nicht braucht, dann hätte man umsonst Performance für einen JOIN verbraten....

          => Wie mans macht ists Mist. "Object Relational Impedance mismatch" eben

          In Hibernate muss ich mich zwingend einlesen die nächsten Wochen.
          In dem oberen Beispiel wäre es aber womöglich besser, einmal ein JOIN zu nutzen, anstatt für alle User extra nochmals ein Request zu tätigen. (Denke ich mal)
          Für sowas braucht man man sicherlich auch viel Erfahrung und das kleine Geschick, welches ich überhaupt nicht habe :-)

          Grüße

      2. Übrigens Peter,
        du hattest mir ja bzgl. MVC Patterns usw. vor einiger Zeit sehr geholfen gehabt. Wir haben nun die Noten für das Projekt erhalten.
        Habe eine 1.0 erhalten :-)
        Nochmals danke an alle, die mir nützliche Tipps gegeben haben, speziell an Dich.

        Grüße

        1. Servus!

          Übrigens Peter,
          du hattest mir ja bzgl. MVC Patterns usw. vor einiger Zeit sehr geholfen gehabt. Wir haben nun die Noten für das Projekt erhalten.
          Habe eine 1.0 erhalten :-)
          Nochmals danke an alle, die mir nützliche Tipps gegeben haben, speziell an Dich.

          Danke für den Pointer weiter unten. :) Ich war mir nicht sicher, ob Du mich meinst, weil da ja noch einige andere beteiligt waren.
          Sehr schön, wenn es was gebracht hat. Für mich war das immer schon ein Erfolg, wenn sich der Nebel gelichtet hat, und ich ein bisschen weiter sehen konnte. Das hat sich dann auch immer direkt auf die Codequalität ausgewirkt.

          Schöne Grüße,

          Peter

  2. Guten Morgen,

    [...]
    Wie ich aber von meinen Kommilionen gesehen hatte, dass sie Ihre Projekte so gelöst hatten, dass manche eine statische Klasse hatten, um eine Datenbankverbindung aufzubauen. Manche hatten es so gelöst, dass bei einem Login eine Datenbankverbindung aufgebaut wird und erst beim Login wieder abgebaut. Das letztere hört sich nichtmal so schlecht an, wäre das aber dennoch humbuk?

    Zum Rest wurde ja schon was gesagt, aber beim Thema Datenbankverbindungen muss ich noch kurz einhaken. In einer echten Anwendung führt an einem Connection Pool kein Weg vorbei. Eine Lösung mit Connection per User skaliert nicht. Mein Kollege hatte das bei einem Kunden, der mit seinem direkten Konkurrenten fusioniert ist. Eine Webanwendung sollte jetzt von allen bestehenden und den "neuen" Filialen verwendet werden, und hier war auch jeder "Session" eine Connection zugeordnet. Die Admins waren ein wenig überrascht, als aus ~400 Connections plötzlich ~800 wurden. Und eine Datenbankverbindung wird ja in der Regel im Vergleich zur restlichen Geschäftslogik nur kurz benötigt und kann dann zurückgegeben werden an den Pool. Die Unsinnigkeit der Lösung mit *einer* Verbindung in einer statischen Klasse kommentiere ich nicht extra. ;)
    Was man allerdings nicht machen sollte, ist eine eigene Implementierung eines Connection Pools. Es gibt gute und funktionierende Pools, die man verwenden kann.

    Schöne Grüße,

    Peter

    1. Hi Peter,
      danke auch für die Tipps und Anregungen.

      [..] Und eine Datenbankverbindung wird ja in der Regel im Vergleich zur restlichen Geschäftslogik nur kurz benötigt und kann dann zurückgegeben werden an den Pool. Die Unsinnigkeit der Lösung mit *einer* Verbindung in einer statischen Klasse kommentiere ich nicht extra. ;)
      Was man allerdings nicht machen sollte, ist eine eigene Implementierung eines Connection Pools. Es gibt gute und funktionierende Pools, die man verwenden kann.

      Ich würde jetzt sagen, dass eine Datenbankverbindung eigentlich nicht kurz, bzw. selten genutzt wird. Ein kleines Webbeispiel hatte ich in diesem Thread:
      http://forum.de.selfhtml.org/?t=197794&m=1327155
      Pro Klick könnten schon 2-3 Querys entstehen und gelegentlich klickt man sich ja schon öfters mal durch.
      Ich müsste mit dir Poolgeschichte sowieso mal anschauen, wie das genau abläuft. Ohne genau zu wissen, wie die Vorgehensweise ist, würde man ja sicherlich bei einem Aufruf einer Seite, die mehrere Querys hat, sicherlich die Connection die man aus dem Pool hat kurz zwischenspeichern, bis alle 3 Querys abgearbeitet sind, bevor man es in den Pool zurückgibt.

      Grüße

      1. Servus!

        [...]
        Ich würde jetzt sagen, dass eine Datenbankverbindung eigentlich nicht kurz, bzw. selten genutzt wird. Ein kleines Webbeispiel hatte ich in diesem Thread:
        http://forum.de.selfhtml.org/?t=197794&m=1327155
        Pro Klick könnten schon 2-3 Querys entstehen und gelegentlich klickt man sich ja schon öfters mal durch.
        Ich müsste mit dir Poolgeschichte sowieso mal anschauen, wie das genau abläuft. Ohne genau zu wissen, wie die Vorgehensweise ist, würde man ja sicherlich bei einem Aufruf einer Seite, die mehrere Querys hat, sicherlich die Connection die man aus dem Pool hat kurz zwischenspeichern, bis alle 3 Querys abgearbeitet sind, bevor man es in den Pool zurückgibt.

        Wahrscheinlich war der Begriff "Geschäftslogik" hier von mir missverständlich gewählt. Bei der Durchführung eines Algorithmus, also bei der Ausführung einer Anfrage des Benutzers ist Datenbankaktion natürlich wahrscheinlich. Allerdings klickt der User nicht ununterbrochen, sondern liest zwischendrin, holt sich einen Kaffee, ... Bei einer sessionbasierten Anwendung würde ich die eigentliche Zugriffszeit auf die Datenbank im Vergleich zur Sessionlaufzeit auf < 1% schätzen. Das heißt, zu über 99% hält der Nutzer seine Session fest (bzw. der Server für ihn), obwohl er sie nicht braucht. Das Beispiel meines Kollegen hat gezeigt, dass diese ~800 exklusiven Connections durch weit unter 100 gepoolten Connections (ich glaube, 15 oder 25 wurden dann verwendet) ersetzt werden konnten.
        Das ist schon ein Unterschied.
        Und vom Connection Pool selbst bin ich meistens durch die Verwendung von JPA oder Hibernate (pur, im Gegensatz zu JPA) komplett abgekapselt. Ich erhalte dann für die Laufzeit einer Hibernate-Session eine Connection. Aber die Kommunikation mit dem Pool wird vom Framework erledigt.

        Schöne Grüße,

        Peter

        Grüße

        1. Servus Peter,

          Wahrscheinlich war der Begriff "Geschäftslogik" hier von mir missverständlich gewählt. Bei der Durchführung eines Algorithmus, also bei der Ausführung einer Anfrage des Benutzers ist Datenbankaktion natürlich wahrscheinlich. Allerdings klickt der User nicht ununterbrochen, sondern liest zwischendrin, holt sich einen Kaffee, ... Bei einer sessionbasierten Anwendung würde ich die eigentliche Zugriffszeit auf die Datenbank im Vergleich zur Sessionlaufzeit auf < 1% schätzen. Das heißt, zu über 99% hält der Nutzer seine Session fest (bzw. der Server für ihn), obwohl er sie nicht braucht. Das Beispiel meines Kollegen hat gezeigt, dass diese ~800 exklusiven Connections durch weit unter 100 gepoolten Connections (ich glaube, 15 oder 25 wurden dann verwendet) ersetzt werden konnten.
          Das ist schon ein Unterschied.
          Und vom Connection Pool selbst bin ich meistens durch die Verwendung von JPA oder Hibernate (pur, im Gegensatz zu JPA) komplett abgekapselt. Ich erhalte dann für die Laufzeit einer Hibernate-Session eine Connection. Aber die Kommunikation mit dem Pool wird vom Framework erledigt.

          danke. Dann ist mir klar was Du gemeint hast. Da hast du dann natürlich recht. Ich mache mir dann intensiv Gedanken, ob ich Hibernate einsetze oder bei etwas kleineren Projekten den Connection Pool direkt anspreche.

          Übrigens, hatte noch für dich einen Beitrag verfasst, welches ich jedoch an die falsche Stelle platziert habe :-)
          http://forum.de.selfhtml.org/?t=197794&m=1327722

          Grüße