【问题标题】:OptimisticLockException with Ebean and Play Framework 2OptimisticLockException 与 Ebean 和 Play Framework 2
【发布时间】:2012-09-27 08:59:44
【问题描述】:

我将 Ebean 与 Play Framework 2 一起使用,有时它会遇到此类 OptimisticLockException:

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]]]

当很少有参与者开始访问数据库时会发生这种情况。

所以,Manager 类是:

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() 和 update() 钩子用来代替 @PrePersist 注释,因为 Ebean 不支持它。 据我所知,@Version 注解总是会带来乐观锁模式,所以我开始使用这种技巧。我知道 Optimistick 锁是什么,但是这种情况应该如何解决,当许多参与者应该修改同一个数据库记录时,最后一次修改在哪里获胜?

【问题讨论】:

    标签: playframework-2.0 ebean


    【解决方案1】:

    Solution:

    问题:直接从 Play Form 保存分离的 EBean 模型会导致 OptimisticLockException,或者在使用 @Version 时会导致 NullpointerException。

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

    解决方案:表单应该支持在从请求参数绑定之前从数据库中提供一个对象。然后在请求中找到的参数应该覆盖对象上的相关属性。也许在 bindFromRequest() 之前调用 fill():

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

    【讨论】:

    • 是的,你说得对。但我的麻烦不在这里。问题出在类层次结构深处的@Version 注释中。无论如何,您的回答对于第一次遇到此类麻烦的人非常有用。让它被接受。
    • 如何让id在表单绑定前调用Venue.find.byId(id))
    【解决方案2】:

    我解决了这个 OptmistLockException 问题,只是在尝试更新时将实体 ID 传递给了控制器。为了防止用户更改值,该值作为隐藏字段传递。

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

    在控制器端,我检查收到的表单是否有错误。在否定的情况下,我会更新表单中的附加实体。

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

    【讨论】:

    • 任何聪明的用户都可以从 UI 中查看并且最重要的是更改隐藏字段的值。这不是一个好的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多