| 

.NET C# Java Javascript Exception

Endlosschleife bei update bzw. select in beforeDelete

Dies ist das Archiv des ehemaligen Forums zum Thema Groovy, Grails, Griffon und Bean Scripting Framework, welches unter groovy-forum.de existierte. Die neue Adresse des Groovy-Forums ist: http://codekicker.de/fragen/themen/groovy.


Endlosschleife bei update bzw. select in beforeDelete

Stapitol - 16.08.2009 09:40
Ich habe eine Domain-Klasse, die sieht z.B. so aus:
Language: Groovy
class ForumCategory{ //... int pos; //... def beforeInsert = { pos=ForumCategory.count()+1; } def beforeDelete = { //... println ""+this.pos; } }

Wird gelöscht, wird einmal die Position, im Beispiel 11, ausgegeben. Nun gibt es, aufgrund von anderen Codezeilen, die Anforderung, dass "pos" fortlaufen sein muss. Also wollte ich einfach beim Löschen alle nachfolgenden "pos"-Werte um eins verringern, dazu habe ich folgendes ans Ende von "beforeDelete" angehangen:
Language: Groovy
ForumCategory.executeUpdate( "update ForumCategory c set c.pos=c.pos-1 where c.pos>:p1", ["p1":(this.pos)] ); println "fertig";

Doch leider ist die Ausgabe jetzt eine größere Anzahl an Zeilen mit 11 und am Ende stürzt er dann mit folgendem Fehler ab:
java.lang.StackOverflowError
at $Proxy7.doInHibernate(Unknown Source)
at ForumCategory$_closure2.doCall(ForumCategory.groovy:65)
at ForumCategory$_closure2.doCall(ForumCategory.groovy)
at $Proxy7.doInHibernate(Unknown Source)
at ForumCategory$_closure2.doCall(ForumCategory.groovy:65)
at ForumCategory$_closure2.doCall(ForumCategory.groovy)
at $Proxy7.doInHibernate(Unknown Source)
[...]
Dann habe ich versucht das zu Ändern, indem ich etwas an der Anfrage rumspiele, ohne Erfolg.
Also dachte ich mir "dann eben per Hand":
Language: Groovy
def list=ForumCategory.findAllByPosGreaterThan(this.pos); println "SOOO nun durchgehen"; [...]

Das Ergebnis ist das gleiche, "SOOO nun durchgehen" wird nie ausgegeben, dafür aber die 11 (this.pos) öfters und am Ende ist der Stapelüberlauf.

Dann dachte ich mir, wenn es nicht vorher geht, dann vllt. nachher, also das ganze in afterDelete, doch das war wohl keine gute Idee, da hat es wohl nichts mehr mit Hibernate zu tun:
009-08-15 23:31:48,387 [main] ERROR hibernate.AssertionFailure  - 
  an assertion failure occured (this may indicate a bug in Hibernate, 
  but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: possible nonthreadsafe access to session

Deshalb jetzt meine Fragen:
Wieso löst der Zugriff auf die Tabelle, in der gleich etwas gelöscht werden soll, eine Endlosschleife auf, in der die "beforeDelete" immer wieder aufgerufen wird?
Und wie kann ich das umgehen?
Das Einzige was mir eingefallen ist, ist sich die Position vor dem Löschen zu merken und nach dem "delete()"-Aufruf dann die Aktualisierung aufzurufen, jedes Mal wenn ein delete() aufgerufen werden soll. Das halte ich persönlich für eine ziemlich fehleranfällige Variante. Gibt es Alternativen?

EDIT: Wir verwenden Grails 1.1.

Vielen Dank im Voraus,
Stapitol


Re: Endlosschleife bei update bzw. select in beforeDelete

tkdmatze - 16.08.2009 15:56
Zitat
update ForumCategory c set c.pos=c.pos-1 where c.pos>:p1

alleine bei der Zeile gibbet 2 mögliche fehlerursachen, einerseits die Datenbank und deren Strategie (MS - SQL hat bei sowas riesige Probleme)
und die Persistenz- Schicht Hibernate.

Du versuchst gleichzeitig Sachen abzufragen und zu ändern, wobei die Änderung Auswirkungen auf die Abfrage hat.

In Hibernate kannst du mit dem Befehl flush evtl für Entspannung sorgen.Würde aber nur das Symptom und nicht die Ursache killen.

Besser : Du hast auch eine ID-Spalte (standard bei Grails : Long Unique Auto-Increment)
und eine Abfrage wie
Zitat
update ForumCategory c set c.pos=c.pos-1 where c.id>:p1

würde deine Probleme lösen


Re: Endlosschleife bei update bzw. select in beforeDelete

Stapitol - 16.08.2009 18:04
Als Datanbankgrundlage ist MySQL im Einsatz. Dort habe ich solche Dinge "per Hand" mit SQL schon öfters gemacht und hatte nie Probleme dabei.

Deine Anfrage:
Language: SQL
UPDATE ForumCategory c SET c.pos=c.pos-1 WHERE c.id>:p1
über die ID macht was ganz anderes als von mir gewollt. Hier werden alle Positionen veraendert, die eine ID groesser als die aktuelle Position haben. Die Positionen koennen beliebig verteilt sein, z.B.
pos | id
  1 | 1
  5 | 2
  4 | 3
  3 | 4
  2 | 5
Würde ich jetzt den Eintrag mit ID 3 loeschen, kaeme:
pos | id
  1 | 1
  5 | 2
  2 | 4
  1 | 5
Heraus, damit ist Pos=1 doppelt vergeben, aber 3 und 4 gar nicht, dafuer aber 5.
Jedenfalls lese ich das da heraus.

Ich habe es aber dennoch mal probiert, mit dem Ergebnis:
java.lang.StackOverflowError
at org.codehaus.groovy.tools.RootLoader.loadClass(RootLoader.java:118)
at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:336)
at ForumCategory$_closure2.doCall(ForumCategory.groovy)
at $Proxy7.doInHibernate(Unknown Source)
at ForumCategory$_closure2.doCall(ForumCategory.groovy:69)
at ForumCategory$_closure2.doCall(ForumCategory.groovy)
at $Proxy7.doInHibernate(Unknown Source)
at ForumCategory$_closure2.doCall(ForumCategory.groovy:69)
at ForumCategory$_closure2.doCall(ForumCategory.groovy)
at $Proxy7.doInHibernate(Unknown Source)

Ich wollte auch dein flush:true versuchen, doch ich konnte in der Doku zu executeUpdate nur die beiden schon verwendeten Parameter query und positionalParams gefunden. Wo müsste ich das denn angeben?

Meine Alternative hatte nicht versucht 2 Dinge gleichzeitig zu machen (sondern nach einander), dennoch wurde "beforeUpdate" immer wieder aufgerufen. Oder habe ich da einen Denkfehler?

Danke für den Versuch!


Re: Endlosschleife bei update bzw. select in beforeDelete

Stapitol - 17.08.2009 12:11
Und genau damit versuchst du das Problem zu umgehen. Und dann ist die Anforderung nicht mehr "zusammenhängend, keins doppelt" sondern nur noch "keins doppelt". Da es wirklich rein zur Positionierung ist, ist das möglich. Allerdings erschwert das das Hoch- und Runterschieben, weil es nicht einfach das Element "pos-1" bzw. "pos+1" ist, sondern "Maxmimale, welche kleiner als pos ist" bzw. "Minimale, welche größer als pos ist". Auch lassen sich die (automatisierten) Tests dann nicht so einfach machen, würde ich da den gleichen Code zum Herausfinden nutzen, kann ich mir den Test ja gleich sparen. ;)

Auch würde das mein Problem "Zugriff auf andere Elemente der Klasse in beforeDelete führt zum endlosen rekursiven Aufruf von beforeDelete" nicht lösen. Ich kann nicht sagen, ob ich dieses Problem jemals wieder haben werde. Ich glaube zwar nicht, dass dies der Fall ist, aber das habe ich im Laufe des Projektes schon mehrfach gedacht und dann kam es doch anders.
Ich denke, dass ich nie Grails/Hibernate verstehen werde, wenn ich bei Problem immer das, was ich machen möchte, so ändere, dass ich es auf bekanntes zurückführen kann, auch wenn der Aufwand dann höher ist (das Positionsändern wird potentiell viel öfter gemacht, als das Löschen).

Das ist nicht böse gemeint!

MfG,
Stapitol


Stelle deine Groovy-Frage jetzt!


Diese Seite zeigt den Thread "Endlosschleife bei update bzw. select in beforeDelete" der ehemaligen Webseite groovy-forum.de, welche durch einen Serverunfall zerstört wurde. codekicker.de hat viele Konversationen über die beliebte Programmiersprache Groovy und zugehörige Frameworks wie das Grails-Framework retten können.

Hast Du eine Frage zum Thema Groovy, Grails oder allgemein Java? Viele ehemalige groovy-forum.de Mitglieder beantworten dir auf codekicker.de deine Frage! Stelle jetzt eine Frage!

Viele weitere Diskussionen zu Grails und Groovy befinden sich auf der Threadübersicht des alten groovy-forum.de.