# Hibernate update-Problem



## k4lle (10. Jan 2008)

Ich hoffe mein Topic ist an dieser Stelle richtig.
Ich habe folgendes Problem: Ich schildere kurz die Theorie. Vielleicht verstehe ich ja etwas falsch und kann dann selber weiterbasteln.

Das Speichern eines Objekts:                                           Objektzustand:
- Session & Transaction wird gestartet                               new -> transient              
- Das Objekt wird gespeichert                                           save -> persistent
- Transaction und Session wird beendet                             close -> detached

Das Laden eines Objekts:                                                 
- Session & Transaction wird gestartet 
- das ausgewählte Objekt aus h:dataTable                         load -> persistent
  mit ID=?? wird geladen
- Transaction und Session wird beendet                             close -> detached


Jetzt kommt mein Problem:
Ich will das gerade ausgewählte Objekt aus der Liste updaten. Hierzu wähle ich ein Objekt aus und lasse es mir in einem Formular anzeigen. Jetzt will ich den Button ändern betätigen können und das Objekt soll geupdatet werden. 
Hierzu will ich Operation update() benutzen.

Bisher klappt nur das Updaten eines Objekts, dass ich gespeichert habe und dann sofort wieder update. Sobald ich mich von der Anwendung abmelde und ein beliebiges Objekt aus der Liste auswähle, kann ich dieses nicht updaten. 
Ich bin der Meinung, dass es mit dem Hibernate-Objektzustand zu tun hat. Mir ist klar, dass einiges dazu in der Hibernate-Doku steht, aber wenn ich mir hätte dadurch weiterhelfen können würde ich hier nicht nachfragen 

Es wäre sehr schön, wenn mir jemand die Theorie zum updaten eines Objekts im detached-Zustand sagen könnte.
Außerdem wäre es schön, wenn jemand sagen könnte ob ich mit meinen Objektzuständen die ich oben genannt habe recht habe. Falls ich Code posten soll, kann ich das gerne machen. Es geht mir aber jetzt erstmal um die Theorie.

Vielen Dank...


----------



## SlaterB (10. Jan 2008)

> kann ich dieses nicht updaten. 

wie zeigt sich das?
hat das zu updatende Objekt eine Id gesetzt?

kannst du zum Zeitpunkt des Fehlers auf normalem Wege das Objekt zu dieser Id laden?
ist es vielleicht schon geladen und in der Session vorhanden?
dann könnte ein Update mit einem anderen Objekt Ärger machen,
aber so genau weiß ich das grad auch nicht


----------



## k4lle (10. Jan 2008)

um das ganze besser zu beschreiben folgendes:
es geht nur um das updaten:

habe in meiner DB ca. 20 Objekte.

1) starte meine anwendung
2) wähle aus einer liste die durch eine tabelle dartgestellt wird ein objekt aus
3) dieses objekt lade ich mit hilfe der ID in ein formular (die ID wurde durch Hibernate vergeben)
4) jetzt möchte ich dieses objekt updaten (also einfach durch die Operation update()) 
bis da klappt alles wie es soll

5) ????? welchen Objektzustand hat mein Objekt (laut meinem verständnis hat es den zustand detached)
    wie speichere ich genau ein objekt des zustand detached. muss es nicht zuerst zurück in den zustand persistent um 
    gespeichert zu werden?


wäre schön, wenn du mir erklären könntest, wie der punkt 5) theoretisch aussehen muss?????

PS: Gibt es eine Operation, mit der ich mir den Hibernate-Objektzustand ausgeben lassen kann???? Das würde mir glaube ich absolut weiterhelfen. Dann würde ich mehr verstehen


----------



## SlaterB (10. Jan 2008)

5) Zustand detached, speichern mit update

http://www.devarticles.com/c/a/Java/Hibernate-Understanding-Associations/1/

das sind allerdings nur theoretische Kenntnisse,
ich kann dir da direkt nicht weiterhelfen, auch nicht testen


----------



## *Hendrik (10. Jan 2008)

Hast Du Dir schon mal die Leseprobe hier angeschaut?


----------



## SlaterB (10. Jan 2008)

ne, aber hab das Buch 

das fand ich allerdings recht oberflächlich zu beiden Themen,
was nicht bedeutet, dass ich mehr weiß, vergesse eh das meiste wieder


----------



## happy_robot (11. Jan 2008)

du musst eigentlich nichts anderes machen als "saveOrUpdate" aufrufen nach einer änderung.

den zustand detached hat es erst wenn du ein evict auf dem objekt aufrufst. 
damit werden alle referenzen zum ursprünglichen db-objekt "vergessen".
ansonsten bleibt das objekt immer "attached".
detachte objekte können grundsätzlich kein update erhalten weil der bezug zur datenbank ja gänzlich fehlt.


----------



## k4lle (14. Jan 2008)

also wenn ich mich an das hibernate-zustandsmodell halte, dann gelangen laut meinem verständnis die persistenten objekte nachdem die session geschlossen wird in den zustand detached. 
jetzt lade ich das (detached) objekt und möchte es updaten. 

wenn ich saveorUpdate benutze geschieht folgendes:

ich lade das objekt aus der DB. Zb. ein Objekt mit der ID 34. (ID wird automatisch beim Speichern zugewiesen).
- das sieht wie folgt aus:


```
public String aendernMaschinendaten(){
		System.out.println("ID= " + aMaschinendaten);
		//Session holen und Aufruf der Methode HibernateSessionVerwaltung.getSession()
		Session session = HibernateSessionVerwaltung.getSession();
		//aktuell ausgewähltes Objekt wird geladen
		Maschinendaten dieMaschinendaten = (Maschinendaten) session.load(Maschinendaten.class, aMaschinendaten);
		//Bean Properties erhalten aktuell ausgewählte Werte
		maschinendaten.setBetriebsmittel(dieMaschinendaten.getBetriebsmittel());
...
...
		System.out.println("ID= " + aMaschinendaten);
		return "goaendern";
	}
```

Frage:
muss ich nach dem session.load die transaktion bzw. session beenden, um danach die operation saveorUpdate oder update aufrufen zu können?

jetzt soll im formular durch betätigen des buttons speichern saveorUpdate oder update aufgerufen werden.


```
public String updateMaschinendaten(){
	Session session = HibernateSessionVerwaltung.getSession();
	session.saveOrUpdate(maschinendaten);
	return "success";
}
```

in dieser methode hole ich mir eine neue session und will das update durchführen und beende die transaktion und session. 
wenn ich aber saveOrUpdate benutze, ein objekt aus der liste auswähle, es verändere und auf speichern drücke wird immer ein neues objekt angelegt anstatt das alte zu updaten. 
wenn ich update durchführe bekomme ich folgende exception:

```
org.hibernate.TransientObjectException: The given object has a null identifier: beans.Maschinendaten
```
d.h. für mich, dass das objekt unbekannt ist und sich im zustand transient befindet. 

Es treten also folgende Fragen auf:
1) Muss ich nach der Operation aenderbMaschinendaten die Transaktion und Session schließen?
2) Wenn ich die Operation updateMaschinendaten starte ich eine neue Transaktion und Session und beende diese nach dem updaten wieder. ist das so richtig?

ich hoffe es ist einigermaßen verständlich was ich hier schreibe. ich werde mir jetzt noch mal in ruhe die theorie durchlesen und das kapitel objects in der hibernate-referenz angucken. Naja habe ich zwar schon oft genug gemacht, aber schlau bin ich bisher auch nicht so richtig geworden. falls jemand versteht was ich für ein problem habe, dann wäre es schön wenn er mir das kur schildern und erklären könnte....


----------



## happy_robot (14. Jan 2008)

k4lle hat gesagt.:
			
		

> also wenn ich mich an das hibernate-zustandsmodell halte, dann gelangen laut meinem verständnis die persistenten objekte nachdem die session geschlossen wird in den zustand detached.


richtig. aber warum schliesst du die session?



			
				k4lle hat gesagt.:
			
		

> jetzt lade ich das (detached) objekt und möchte es updaten.


die session ist geschlossen. was willst du hier noch laden? 



			
				k4lle hat gesagt.:
			
		

> wenn ich saveorUpdate benutze geschieht folgendes:
> 
> ich lade das objekt aus der DB. Zb. ein Objekt mit der ID 34. (ID wird automatisch beim Speichern zugewiesen).


Nein. saveOrUpdate lädt nichts! Es speichert ein Objekt. Wenn der primaryKey == null wird ein neues angelegt, ansonsten das mit dem primaryKey ge-"updated".



			
				k4lle hat gesagt.:
			
		

> muss ich nach dem session.load die transaktion bzw. session beenden, um danach die operation saveorUpdate oder update aufrufen zu können?


Wenn die Session beendet ist kannst Du nicht mehr auf die Datenbank zugreifen. Alle Lese- und Schreibzugriffe werden fehlschlagen. Lass die Session doch während der ganzen Sitzung geöffnet.  saveOrUpdate würde ich immer in einer Transaktion aufrufen.



			
				k4lle hat gesagt.:
			
		

> jetzt soll im formular durch betätigen des buttons speichern saveorUpdate oder update aufgerufen werden.
> 
> 
> ```
> ...


hier holst du nur eine session und schreibst daten. es wird weder eine transaktion begonnen noch beendet



			
				k4lle hat gesagt.:
			
		

> wenn ich aber saveOrUpdate benutze, ein objekt aus der liste auswähle, es verändere und auf speichern drücke wird immer ein neues objekt angelegt anstatt das alte zu updaten.


ja...weil ein detachtes objekt immer den primaryKey null hat, welches beim schreiben dazu führt daß ein neues objekt angelegt wird. wenn du ein objekt liest und dann die session schliesst kriegen alle bisher gelesenen objekte den primaryKey null zugewiesen. deswegen: session geöffnet lassen!



			
				k4lle hat gesagt.:
			
		

> wenn ich update durchführe bekomme ich folgende exception:
> 
> ```
> org.hibernate.TransientObjectException: The given object has a null identifier: beans.Maschinendaten
> ...


richtig...der primaryKey ist ja auch null. ihm fehlt ja nun der bezug auf den datensatz den er in der DB updaten soll.




			
				k4lle hat gesagt.:
			
		

> Es treten also folgende Fragen auf:
> 1) Muss ich nach der Operation aenderbMaschinendaten die Transaktion und Session schließen?
> 2) Wenn ich die Operation updateMaschinendaten starte ich eine neue Transaktion und Session und beende diese nach dem updaten wieder. ist das so richtig?


- zu beginn der anwendung die session öffnen.
- erst am ende schliessen
- alle schreiboberationen innerhalb von transaktionen (beginTransaction(), commit())
- generell saveOrUpdate nutzen (zumindest für den Anfang  )

grüße


----------



## k4lle (14. Jan 2008)

ok erstmal vielen dank. 

dazu muss ich folgendes sagen, was du aber natürlich nicht wissen kannst:


```
Session session = HibernateSessionVerwaltung.getSession();
```

durch die HibernateSessionVerwaltung wird die Session und die Transaktion in der Methode getSession() geladen.

ich habe mich natürlich mit einem buch beschäftigt. in diesem buch wird extra gesagt, dass man die session nach einer transaktion immer schließen soll, da ansonsten zu viel ressourcen verbraucht werden. das habe ich versucht zu berücksichtigen. scheinbar nicht mir erfolg . wenn z.b. mehrere benutzer auf die anwendung zugreifen, ist es schlecht wenn 30 sessions gleichzeitig geöffnet sind. wie siehst du das?

so wie du mir das erklärt hast leuchtet mir das absolut ein.
- zu beginn der anwendung session öffnen
- um transaktionen durchzuführen immer transaktionen beginnen und wieder schließen
- bei beenden deranwendung session wieder schließen

wenn ich das so mache und wie bereits erwähnt 30 benutzer die anwendung gleichzeitig benutzen, ist das dann nicht eher schlecht?


PS: es muss doch möglich sein ein Objekt welches wie folgt gespeichert wird, aus der DB wieder laden zu können um änderungen durchführen zu können ?
- session starten
- transaktion beginnen
- objekt speichern
- transaktion beenden
- session beenden

Durch eine gerade gelesenen Text ist mir mittlerweile klar geworden, dass es nicht möglich ist eine objekt in einer session zu laden und in einer anderen zu verändern, bevor die erste session nicht geschlossen ist.

daraus schließe ich, wenn die erste session aber beendet wird kann ich in einer weiteren session das objekt verändern, wenn ich es an diese session binde. 

wäre schön wenn du noch mal kurz was dazu sagen könntest?


----------



## happy_robot (14. Jan 2008)

also die session bei jedem zugriff zu öffnen und zu schliessen ist alles andere als sinnvoll und wird deine anwendung ganz schön ausbremsen, da dafür sehr viel zeit verloren geht. wenn du da keinen guten connection-pool hast dauert jeder zugriff etliche sekunden.

dieses buch scheint kein sehr gutes buch zu sein........... 

es ist kein problem mit einer session 30 benutzern zugriff zu geben. besser wäre es aber sicherlich wenn du jedem benutzer eine eigene session gibst und sie bis zum abmelden des users geöffnet hälst also erst beim abmelden schliesst.

also so:

- Anmeldung (Session öffnen)
- n x (beginTransaction()...saveOrUpdate()....commit())
- Abmeldung (Session schliessen)

mfg


----------



## k4lle (14. Jan 2008)

ok, das ist leuchtet mir ein. 

ich werde es jetzt so machen: 

1) benutzer loggt sich ein (session wird geöffnet)
2) benutzer arbeitet mit der anwendung (transaktion geöffnet, z.b. update, transaktion geschlossen) 
3) benutzer meldet sich ab (session wird geschlossen)

das bedeutet, dass ich einiges an meiner anwendung ändern muss. 

ich hoffe das ist also die optimalste lösung. naja ich vertrau dir einfach mal. mir bleibt auch nichts anderes übrig, da ich bei mir so einfach nicht weiter komme und so wie du mir das erklärt hast kann ich es absolut nachvollziehen.

vielen dank. mal sehen ob später alles so läuft wie es soll. 

PS: was passiert eigentlich wenn 2 benutzer gleichzeitig mit der anwendung arbeiten und der eine z.b. updatet und der andere kurz danach auch. kann es da zu problemen kommen? naja darum sollte ich mir vielleicht erstmal später gedanken machen....


----------



## happy_robot (14. Jan 2008)

k4lle hat gesagt.:
			
		

> PS: was passiert eigentlich wenn 2 benutzer gleichzeitig mit der anwendung arbeiten und der eine z.b. updatet und der andere kurz danach auch. kann es da zu problemen kommen?


zu problemen kommt es da datenbanktechnisch nicht. das ist aber auch nicht aufgabe der datenbank dieses zu lösen. es kann ja zum beispiel sein daß du genau dieses verhalten haben willst. die DB kann davon nichts wissen. sie macht nur daß was du ihr sagst.

ich würde dir raten die ganzen zugriffe auf die datenbank in einer klasse zu kapseln statt immer die direkten methoden aufzurufen. dann kannst du dies nachher im nachhinein sehr gut koordinieren.


----------



## byte (14. Jan 2008)

Ich würde mir die Session über SessionFactory#getCurrentSession() holen. Du brauchst Dir dann gar keine Gedanken über das Öffnen und Schließen der Session machen. Die Session wird automatisch beim Commit geschlossen. Über die Hibernate Konfiguration kannst Du dann die Stategie einstellen, wann eine neue Session gestartet wird, z.B. beim Zugriff durch einen neuen Thread (hibernate.current_session_context_class=thread). Noch besser: JTA mit Spring.
Die Hibernate Zustände brauchen Dich dabei eigentlich gar nicht zu kümmern (zumindest bei einfachen Dingen), denn getCurrentSession() liefert Dir immer die richtige Session, so dass Du das Objekt auch speichern kannst.

Details siehe: http://www.hibernate.org/42.html


----------



## k4lle (14. Jan 2008)

ok vielen dank erstmal. ich werde jetzt mal versuchen alles ein wenig zu ändern. da mir die theorie schon mal einleuchtet  , müßte (hoffentlich) alles so klappen wie ich mir das vorstelle. 

ich melde mich später mal und erstatte bericht.

ich finde das manchmal sehr schwierig mit büchern zu arbeiten. natürlich bekommt man da vieles erklärt, aber wenn dann mal wirklich ne frage auftaucht, dann findet man oft keine antwort. naja dazu gibt es ja zum glück foren.


----------



## byte (14. Jan 2008)

Hibernate ist auch nicht umbedingt ein triviales Framework. Ich durchblicke da längst auch nicht alles. Aber die Doku auf hibernate.org ist eigentlich ganz brauchbar. Da findet man viele nützliche Hinweise, wenn man sich die Zeit nimmt, genau zu suchen. Anderes hingegen ist aber auch dort etwas knapp abgehandelt.


----------



## happy_robot (14. Jan 2008)

byto hat gesagt.:
			
		

> Ich würde mir die Session über SessionFactory#getCurrentSession() holen. Du brauchst Dir dann gar keine Gedanken über das Öffnen und Schließen der Session machen. Die Session wird automatisch beim Commit geschlossen.


stimmt nicht so ganz. hibernate nutzt hier ja indirekt den standard-connection-pool der benutzten datenbank. die verbindung wird also nicht geschlossen sondern nur neu zugeteilt. das schaut bei wenigen usern ganz prima aus. wenn die anzahl der benötigten sessions größer als der pool wird, wird erst mit dem schliessen und öffnen begonnen. dann fällt die performance rapide ab.



			
				byto hat gesagt.:
			
		

> getCurrentSession() liefert Dir immer die richtige Session, so dass Du das Objekt auch speichern kannst.


ja, da die session an einen ThreadLocal gebunden ist. 

das automatische öffnen und schliessen durch das framework scheint im ersten moment sehr elegant zu sein, wird aber zum krampf wenn man mal savepoints und rollbacks implementieren will.


----------



## k4lle (14. Jan 2008)

es geht einfach immer noch nicht meinen kopf rein was passiert wenn:

folgendes szenario ist mir klar:
- benutzer meldet sich an (session wird geöffnet)
- führt transaktionen durch (trans öffnen, z.b. update, trans schließen)
- benutzer meldet sich ab (session wird geschlossen)

aber was ist denn wenn der benutzer sich zum zweiten mal anmeldet (was natürlich der fall ist)
- benutzer meldet sich an (session wird geöffnet)
*- jetzt läd er ein objekt aus der db, welches in einem form dargestellt wird und will es updaten
  das klappt einfach nicht, da das geladene objekt den primary key null hat. kann ich mir auch noch vorstellen, weil es in 
  der session zuvor gespeichert wurde. dieses szenario muss aber möglich sein!!!!! ich habe scheinbar immer noch nicht   
  genau verstanden wie das funktionieren soll*
- benutzer meldet sich ab (session wird geschlossen)

bisher ist es in meiner anwendung so, wenn sie gestartet wird, wird das configurations-objekt und die sessionfactory erzeugt und dann öffne ich über die sessionfactory die session.

wäre schön, wenn ihr mir noch mal was zu dem fettgeschriebene sagen könntet.


----------



## happy_robot (14. Jan 2008)

k4lle hat gesagt.:
			
		

> *- jetzt läd er ein objekt aus der db, welches in einem form dargestellt wird und will es updaten
> das klappt einfach nicht, da das geladene objekt den primary key null hat. kann ich mir auch noch vorstellen, weil es in
> der session zuvor gespeichert wurde. dieses szenario muss aber möglich sein!!!!! ich habe scheinbar immer noch nicht
> genau verstanden wie das funktionieren soll*


wenn du mit hibernate ein objekt aus der DB geladen hast kann es keinen null-key haben.


----------



## byte (14. Jan 2008)

happy_robot hat gesagt.:
			
		

> byto hat gesagt.:
> 
> 
> 
> ...


Ich habe doch gar nicht von DB-Connections gesprochen sondern von Sessions. Bei getCurrentSession() wird die Session geschlossen, sobald das commit() kommt. Allerdings erzeugt Hibernate intern einen Proxy, die eigentliche Session bleibt offen je nach Strategie.



> byto hat gesagt.:
> 
> 
> 
> ...


Ich habe auch nicht gesagt, dass Thread Local Sessions immer ideal sind sondern es nur als eine (einfache) Möglichkeit eröffnet. Natürlich ist es bei komplexeren Sachen sinnvoll, das anders zu machen. Dann verwendet man idealerweise Spring fürs Session und Transaction Handling und erspart sich somit viel Arbeit und Ärger.


----------



## k4lle (14. Jan 2008)

ja dann muss also mein fehler definitiv beim laden sein. solange eine session geöffnet ist und ich mir ein objekt aus der db lade kann es also keinen null-key haben. 

User meldet sich an (Session wird geöffnet)

lade Objekt aus DB mit


```
Maschinendaten dieMaschinendaten = (Maschinendaten) session.load(Maschinendaten.class, aMaschinendaten);
```

dann muss ich jetzt ein update auf das geladene Objekt durchführen können

jetzt beendet ich die session (User meldet sich ab) 

(vor allen Transaktionen wird die trans gestartet und danach beendet)


wenn das so gehen muss, dann habe ich einfach irgendwo einen fehler und muss mich einfach jetzt intensiv mit meinem programm weiter beschäftigen bis es endlich klappt.

also so muss es gehen?

diese frage noch benatworten und dann lasse ich euch erstmal in ruhe :-(


----------



## happy_robot (14. Jan 2008)

byto hat gesagt.:
			
		

> Ich habe doch gar nicht von DB-Connections gesprochen sondern von Sessions. Bei getCurrentSession() wird die Session geschlossen, sobald das commit() kommt. Allerdings erzeugt Hibernate intern einen Proxy, die eigentliche Session bleibt offen je nach Strategie.


ok, die connection wird über die SessionFactory aufgebaut. die wiederum konfiguriert auch den eigenen c3p0-connection-pool, was doch nahelegt daß hier auch die verbindungen gemanaged werden und bei bedarf geöffnet oder geschlossen werden. das ist  ein wenig undurchsichtig, trotzdem liegt es nahe daß jeder eigene thread eine eigene verbindung für seine sessions kriegt. und somit hast du bei 100 threads schnell immer 100-(connectionpool-size) neue verbindungen was das ganze ausbremst.



			
				byto hat gesagt.:
			
		

> Ich habe auch nicht gesagt, dass Thread Local Sessions immer ideal sind


ich auch nicht


----------



## happy_robot (14. Jan 2008)

k4lle hat gesagt.:
			
		

> ```
> Maschinendaten dieMaschinendaten = (Maschinendaten) session.load(Maschinendaten.class, aMaschinendaten);
> ```


was ist hier "aMaschinendaten);"? das sollte ein Integer mit dem primary-key sein.



			
				k4lle hat gesagt.:
			
		

> diese frage noch benatworten und dann lasse ich euch erstmal in ruhe :-(


kein problem


----------



## k4lle (14. Jan 2008)

das ist genau der Integer mit dem Primary-Key. Er läd mir das ausgewählte Objekt in ein Formular. 

Also habe ich mit meinem letzten post recht?
wenn ich damit recht habe, dann weiß ich zumindest was ich zu tun habe. Ansonsten habe ich kein Bock mehr und schmeiß den ganzen scheiß weg ;-)


----------



## byte (14. Jan 2008)

happy_robot hat gesagt.:
			
		

> byto hat gesagt.:
> 
> 
> 
> ...


Den Connection Pool kannst Du ja über die Hibernate Config definieren. Die wird dann über die SessionFactory geladen, das ist richtig.
Aber Du hast glaube ich einen Denkfehler (oder ich verstehe Dich falsch  ): Es besteht *keine* 1:1 Beziehung zwischen Hibernate Session und DB-Connection! Der Common Way ist das Session-Per-Request Pattern (siehe hier). Häufig wird jeder Request in einem eigenen Thread bearbeitet, das heisst jeder Request wird in einem Thread mit einer Session in einer Transaktion abgehandelt. Das heisst aber nicht zwangsläufig, dass auch jede Session eine eigene DB-Connection bekommt.



			
				Hibernate Doku hat gesagt.:
			
		

> A Session is an inexpensive, non-threadsafe object that should be used once, for a single request, a conversation, single unit of work, and then discarded. A Session will not obtain a JDBC Connection  (or a Datasource) unless it is needed, hence consume no resources until used.


----------



## ms (14. Jan 2008)

Reden wir hier von einem Rich Client oder einer Webapplikation?

ms


----------



## happy_robot (14. Jan 2008)

byto hat gesagt.:
			
		

> Aber Du hast glaube ich einen Denkfehler (oder ich verstehe Dich falsch  ): Es besteht *keine* 1:1 Beziehung zwischen Hibernate Session und DB-Connection!


das ist schon klar  

mir ging es darum daß du nicht unbedingt darauf vertrauen solltest das bei getCurrentSession() nicht doch auch wieder eine neue verbindung aufgemacht wird. wenn du mehr threads hast als im pool liegen geht der ärger los.

ich mache es zum beispiel immer so daß ich eine vorher definierte anzahl an verbindungen öffne (1-n) und die kandidaten die an die datenbank wollen können sich jeweils eine vebindung abholen. diese wird dann mittells semaphore gesperrt bis der zugriff abgeschlossen ist und der nächste der dran will muss solange an der semaphore warten. lässt sich prima loggen und koordinieren. auf automatismen zu vertrauen habe ich mir hier abgewöhnt.

das fragment aus der hibernate-doku erstaunt mich etwas. bei mir klappt das ganz prima.


----------



## k4lle (14. Jan 2008)

happy sag bitte noch mal was zu meinem letzten poste


----------



## happy_robot (14. Jan 2008)

k4lle hat gesagt.:
			
		

> happy sag bitte noch mal was zu meinem letzten poste


wenn da eine not-null id als primary-key drin steht is doch alles gut.
wenn jetzt allerdings die session geschlossen ist schlägt ein update in jedem falle fehl. 
in der session in der du das ding geladen hast muss auch das update erfolgen.


----------



## k4lle (15. Jan 2008)

jetzt weiß ich wo das problem genau liegt. zum testen speichere ich nach dem start der anwendung mehrere objekte. das klappt auch ohne weiteres. alle operationen öffnen und schließen nur transaktionen. die session schließe ich beim abmelden.

Operation zum öffnen der Session

```
public Session oeffneaktuelleSession(){
		aktuelleSession = HibernateSetup.getSessionFactory().openSession();
		return aktuelleSession;
	}
```

Operation zum speichern der objekte

```
public String saveMaschinendaten(){
		Transaction transaction = oeffneaktuelleSession().beginTransaction();
		System.out.println("Transaction gestartet");
		aktuelleSession.save(maschinendaten);
		transaction.commit();
		return "success";
	}
```

Operation zum laden eines Objekts, welches in einem Formular dargestellt wird.

```
public String aendernMaschinendaten(){
		System.out.println("ID= " + aMaschinendaten);
		Transaction transaction = oeffneaktuelleSession().beginTransaction();
		Maschinendaten dieMaschinendaten = (Maschinendaten) aktuelleSession.load(Maschinendaten.class, aMaschinendaten);
		maschinendaten.setBetriebsmittel(dieMaschinendaten.getBetriebsmittel());
		maschinendaten.setDokumentation(dieMaschinendaten.getDokumentation());
		maschinendaten.setSiehe(dieMaschinendaten.getSiehe());
                ...
                ...
		transaction.commit();
		return "goaendern";
	}
```

Wird aufgerufen wenn im formular speichern gedrückt wird

```
public String updateMaschinendaten(){
		Transaction transaction = oeffneaktuelleSession().beginTransaction();
		aktuelleSession.saveOrUpdate(maschinendaten);
		transaction.commit();
		return "success";
	}
```

das laden aus der db klappt nicht richtig. es passiert immer folgendes. egal ob ich update oder saveorupdate benutze. um das zu verdeutlichen beschreibe ich das mal.
- Ich speichere 2 Objekte ab mit folgenden Werten (nur als beispiel) 
   1) ID = 1, Name = Tim, Alter = 23
   2) ID = 2, Name = Christian, Alter = 24
- Jetzt lade ich mir durch die aendernMaschinendaten() ein objekt aus der DB. ich will das 1) objekt laden. hierzu lasse 
  ich mir zum test mit System.out.println(aMaschinendaten); die ID ausgeben. Es wird die ID = 1 angezeigt und 
  schließlich das objekt in einem formular angezeigt. bis dahin ist alles wunderbar.
- jetzt will ich das geladene objekt verändern und die updateMaschinendaten() aufrufen. 
  Es passiert aber immer folgendes. Obwohl das 1 Objekt geladen ist (meiner meinung nach), wird beim aufruf der 
  methode updateMaschinendaten() immer nur das zuletzt durch die methode saveMaschinendaten() gespeicherte 
  Objekt verändert. in diesem fall wird also das Objekt 2 geupdatet, da dieses zuletzt gespeichert wurde. 

Wieso ist das so? Mache ich beim Laden etwas falsch? Ich hoffe das ist verständlich und Ihr Profis könnt mir schnell dazu was sagen. Jetzt öffne ich nur eine Session und trotzdem klappt das nicht richtig. Wo mache ich denn was falsch?[/quote]


----------



## ms (15. Jan 2008)

In allen deinen Codesnippets, die du angeführt hast, erzeugst du jedesmal eine neue Session.
byto hat oben schon gesagt, dass es SessionFactory.currentSession() gibt um die aktuelle Session zu bekommen.

Übrigens wurde meine Frage von oben bisher noch nicht beantwortet.
Ich gehe jetzt mal davon aus, dass wir hier von einer Webapplikation reden.



			
				k4lle hat gesagt.:
			
		

> - jetzt will ich das geladene objekt verändern und die updateMaschinendaten() aufrufen.


Bitte erkläre ganz genau was du mit 'verändern' meinst.
Sind das zwei verschiedene Requests?

ms


----------



## k4lle (15. Jan 2008)

ok. ich rufe ja auch immer die oeffneaktuelleSession() auf und dort wird dann immer wieder eine neue session erzeugt. so will ich das natürlich nicht. 
es geht hier um eine webapplikation. 

also session öffnen und dann kann ich mittels SessionFactory.currentSession jeder Zeit auf die aktuelle Session zugreifen. 

ich benutze JSF, lade mir über einen dataTable mein ausgewähltes objekt in ein formular und will dann durch betätigen eines buttons in Hibernate saveOrUpdate() oder update() ausführen. durch betätigen wird die action-methode updateMaschinendaten() aufgerufen, welche die Hibernate Transaction durchführt.

also kann es bisher nur daran liegen, dass ich immer wieder neue sessions geöffnet habe?


----------



## ms (15. Jan 2008)

Es reicht, wenn du immer SessionFactory.currentSession() aufrufst. Diese Methode kümmert sich schon um das erstmalige Öffen der Session.


```
public String aendernMaschinendaten(){
      System.out.println("ID= " + aMaschinendaten);
      Transaction transaction = oeffneaktuelleSession().beginTransaction();
      Maschinendaten dieMaschinendaten = (Maschinendaten) aktuelleSession.load(Maschinendaten.class, aMaschinendaten);
      maschinendaten.setBetriebsmittel(dieMaschinendaten.getBetriebsmittel());
      maschinendaten.setDokumentation(dieMaschinendaten.getDokumentation());
      maschinendaten.setSiehe(dieMaschinendaten.getSiehe());
                ...
                ...
      transaction.commit();
      return "goaendern";
   }
```
Hier fällt mir nur auf, dass es zwei Variablen vom Typ Maschinendaten gibt.
Allerdings wird nicht die geladene (dieMaschinendaten) geändert sondern die andere (maschinendaten).

ms


----------



## k4lle (15. Jan 2008)

also wenn ich SessionFactory.getCurrentSession() benutze muss ich mich um nichts kümmern außer vor den DB-Transaktionen die transaction zu beginne und danach zu beenden. ist das soweit richtig?


----------



## byte (15. Jan 2008)

Ja, das habe ich oben doch schon geschrieben. Im übrigen würde ich Dir für Webanwendungen das Open Session in View Pattern ans Herz legen (eine Transaction pro Request). Das kombinierst Du am besten mit dem DAO Pattern, dann wird Dein Code auch etwas logischer und man findet leichter Fehler (eine Methode aendernMaschinendaten(), die Klassenvariablen per Hibernate in die DB schreibt, ist großer BS, sorry  ).


----------



## k4lle (15. Jan 2008)

kein problem. kannst du ruhig sagen. ich kann das bloß jetzt nicht mal eben immer wieder alles ändern. fürs nächste mal weiß ich bescheid. ich habe mich halt bisher nur an bücher gehalten. und da wird es so gemacht wie ich es versuche. 

naja ich mach mal weiter. ich habe zwar keine hoffnung mehr, aber da muss man wohl durch. ich hoffe spätestens morgen klappts. ansonsten schlag ich alles kaputt.


----------



## k4lle (16. Jan 2008)

So jetzt klappt endlich alles so wie ich mir das vorgestellt habe. Als kleines Beispiel möchte ich euch mal eine Methode zeigen und ihr sollt sagen was ich vielleicht beim nächsten mal anders machen sollte. Außerdem wäre ich euch sehr verbunden, wenn ihr mir noch mal die genau Funktionsweise von getCurrentSession() erklären könnt. Natürlich verstehe ich was bisher dazu geschrieben wurde, aber falls es noch ein weinig detaillierter geht wäre das super.


```
public String saveMaschinendaten(){
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSetup.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			session.save(maschinendaten);
			transaction.commit();
		}
		catch(HibernateException e){
			if (transaction != null) {
				transaction.rollback();
				throw e;
			}
		}
		return "success";
	}
```

Vielen Dank für alle Hilfe. Wenigstens habe ich jetzt eine Basis, auf der ich aufbauen kann.


----------

