2012-09-27 30 views
7

estoy usando Ebean con Play marco 2 y, a veces cae con OptimisticLockException de este tipo:OptimisticLockException con Ebean and Play Marco 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]]] 

Esto sucede cuando algunos actores comienzan a tener acceso a la base de datos.

Por lo tanto, la clase Manager es:

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(); 
} 

} 

Guardar ganchos() y update() se utilizan anotaciones en lugar @PrePersist, debido Ebean no lo soporta. Como sé @Version Annotation siempre trae el modo de bloqueo optimista, así que empiezo a usar ese truco. Sé lo que es el bloqueo de Optimistick, pero ¿cómo debería resolverse esta situación, cuando muchos actores deberían modificar el mismo registro de db, donde gana la última modificación?

Respuesta

15

Solution:

El problema: Guardar un modelo Ebean adosado directamente desde el Formulario de reproducción hace que sea OptimisticLockException, o cuando se utiliza @Version que provoca NullPointerException.

Form<Venue> form = form(Venue.class).bindFromRequest(); 
form.get().update(id); // this causes the exception 

La solución: El formulario debe admitir el suministro de un objeto desde la base de datos, antes de enlazar desde los parámetros de solicitud. Los parámetros encontrados en la solicitud deben sobrescribir las propiedades relevantes en el objeto. Tal vez llame relleno() antes de bindFromRequest():

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

Sí, tienes razón. Pero mi problema no estaba aquí. El problema estaba en la anotación @Version en lo profundo de la jerarquía de clases. De todos modos, tu respuesta es muy útil para alguien que se enfrenta a tales problemas por primera vez. Deja que sea aceptado. –

+0

¿Cómo se obtiene ** id ** para llamar a * Venue.find.byId (id)) * antes del enlace del formulario? –

2

que resuelven este problema OptmistLockException simplemente pasando el identificador de entidad al controlador cuando se trata de actualizar. Para evitar que el usuario cambie los valores, el valor se pasó como un campo oculto.

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

En el lado del controlador, compruebo si el formulario recibido tiene errores. En caso negativo, actualizo la entidad adjunta en el formulario.

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

Cualquier usuario inteligente podrá ver y, lo más importante, ** cambiar ** el valor del campo oculto de la IU. Esta no puede ser una buena solución. –

Cuestiones relacionadas