2012-09-27 5 views
7

Ich verwende Ebean mit Play Framework 2 und manchmal fällt es mit OptimisticLockException solchen Art:OptimisticLockException mit Ebean und Play Framework 2

play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[OptimisticLockException: Data has changed. updated [0] rows sql[update manager set modification_time=?, session_id=?, expiration_date=? where id=? and rating=? and creation_time=? and modification_time=? and name=? and surname=? and login=? and password_hash=? and email=? and session_id=? and expiration_date=?] bind[null]]] 

Dies geschieht, wenn einige Akteure Datenbank zuzugreifen starten.

So Manager-Klasse ist:

public class Manager extends Model { 
@Getter @Setter 
Long id; 

@Getter @Setter 
private String name; 

@Getter @Setter 
private String surname; 

@Column(unique = true) 
@Getter @Setter 
private String login; 

@Getter @Setter 
private String passwordHash; 

@Getter @Setter 
private String email; 

@Embedded 
@Getter @Setter 
private ManagerSession session; 

@Getter 
private Timestamp creationTime; 

@Getter 
private Timestamp modificationTime; 

@Override 
public void save() { 
    this.creationTime  = new Timestamp(System.currentTimeMillis()); 
    this.modificationTime = new Timestamp(System.currentTimeMillis()); 
    super.save(); 
} 

@Override 
public void update() { 
    this.modificationTime = new Timestamp(System.currentTimeMillis()); 
    super.update(); 
} 

} 

save() und update() Haken statt @PrePersist Anmerkungen verwendet, weil der Ebean nicht unterstützt. Wie ich weiß, @Version Annotation bringt immer Optimistic Lock-Modus, so beginne ich, einen solchen Trick zu verwenden. Ich weiß, was Optimistick-Sperre ist, aber wie sollte diese Situation gelöst werden, wenn viele Akteure denselben Datenbank-Datensatz ändern sollten, wo die letzte Änderung gewinnt?

Antwort

15

Solution:

Das Problem: ein freistehendes EBean Modell direkt aus dem Play-Formular Speicher verursacht entweder OptimisticLockException, oder wenn @Version Verwendung es verursacht Nullpointer.

Die Lösung: Das Formular sollte die Bereitstellung eines Objekts aus der Datenbank unterstützen, bevor es aus den Anforderungsparametern gebunden wird. Die in der Anfrage gefundenen Parameter sollten dann die relevanten Eigenschaften des Objekts überschreiben. Vielleicht rufen fill() vor bindFromRequest():

Form<Venue> form = form(Venue.class).fill(Venue.find.byId(id)).bindFromRequest(); 
form.get().update(id); 
+0

Ja, Sie haben Recht. Aber meine Probleme waren nicht hier. Problem war in @Version Annotation tief in der Klassenhierarchie. Wie auch immer, Ihre Antwort ist sehr nützlich für jemanden, der solche Schwierigkeiten zum ersten Mal begegnet. Lass es angenommen werden. –

+0

Wie bekommst du ** id ** um * Venue.find.byId (id)) * vor dem Formbinden zu nennen? –

2

Ich löste dieses Problem OptmistLockException nur die ID an die steuernde Instanz vorbei, wenn zu aktualisieren versuchen. Um zu verhindern, dass Benutzer Werte ändern, wurde der Wert als verborgenes Feld übergeben.

<input type="hidden" name="id" value="@formVar(<identifierVariable>).value"/> 

Auf der Steuerungsseite überprüfe ich, ob das empfangene Formular Fehler enthält. Im negativen Fall aktualisiere ich die angehängte Entität im Formular.

public static Result update() { 
    Form<Entity> filledForm = form.bindFromRequest(); 
    if (filledForm.hasErrors()) { 
     flashError("app.oh_snap", "app.change_things"); 
    } else { 
     Entity entity = filledForm.get(); 
     entity.update(); 
    } 
} 
+0

Jeder schlaue Benutzer wird in der Lage sein, den Wert des ausgeblendeten Feldes in der Benutzeroberfläche anzuzeigen und vor allem ** zu ändern **. Dies kann keine gute Lösung sein. –