【问题标题】:OptimisticLockException with Ebean/PlayEbean/Play 的 OptimisticLockException
【发布时间】:2013-12-02 22:15:26
【问题描述】:

我有一个使用 Ebean 的 Play 2.1.3 Java 应用程序。我收到下面的 OptimisticLockException。

[OptimisticLockException: Data has changed. updated [0] rows sql[update person 
set name=? where id=? and email=? and name=? and password is null and created=? 
and deleted is null] bind[null]]

我知道它试图告诉我记录在我阅读和尝试写入之间发生了变化。但唯一的变化发生在这种方法中。

public void updateFromForm(Map<String, String[]> form) throws Exception {
    this.name = form.get("name")[0];

    String password = form.get("password")[0];
    if (password != null && password.length() != 0) {
        String hash = Password.getSaltedHash(password);
        this.password = hash;
    }

    this.update();
}

我做错了吗?我在 zentasks 中看到了类似的逻辑。另外,我应该能够看到绑定变量的值吗?

更新:我从控制器内部调用 updateFromForm():

@RequiresAuthentication(clientName = "FormClient")
public static Result updateProfile() throws Exception {

    final CommonProfile profile = getUserProfile();
    String email = getEmail(profile);           
    Person p = Person.find.where().eq("email", email).findList().get(0);

    Map<String, String[]> form = request().body().asFormUrlEncoded();

    if (p == null) {
        Person.createFromForm(form);
    } else {
        p.updateFromForm(form);
    }

    return ok("HI");
}

【问题讨论】:

  • 能否包含调用updateFromForm的方法?
  • 好的,我更新了。我在控制器内调用 updateFromForm() 。 updateFromForm 本身是在模型中定义的。您知道吗?我应该在错误消息中看到绑定变量的值吗?感谢您的帮助。

标签: java jpa playframework playframework-2.1 ebean


【解决方案1】:

我有另一种方法,我在其中添加注释

@EntityConcurrencyMode(ConcurrencyMode.NONE)

到实体类。

这将禁用乐观锁定并发修改检查,这意味着 SQL 变为

update person set name=? where id=?

这更加乐观,因为它只是覆盖了任何中间更改。

【讨论】:

  • @EntityConcurrencyMode 注释在哪个包中?
  • 包 com.avaje.ebean.annotation;
【解决方案2】:

有点晚了,但对于您的情况,@Version 注释应该是解决方案。我们主要将它与java.util.Date 一起使用,因此它也可以用于确定上次记录更新的日期,在 Play 模型中,这只是:

@Version
public java.util.Date version; 

在这种情况下,更新语句将仅使用 idversion 字段 - 特别是在使用大型模型时有用:

update person set name='Bob' 
where id=1 and version='2014-03-03 22:07:35'; 

注意:您不需要/不应该在每次保存时手动更新此字段,Ebean 会自行更新。 version 值仅在更新数据时更改(因此使用 obj.update() 没有任何更改不会更新 version 字段)

【讨论】:

  • 永远不会太晚。事实上,我现在在不同的项目中遇到了同样的问题。当我尝试将 (at)Version 添加到属性(一个用 uuid 填充的字符串)时,它会显示“读取 models.MyModel 的注释时出错”。 (at)Version 是新功能还是已弃用功能?感谢您提供任何见解。
  • 不,它不是旧的或折旧的,可以尝试使用完全合格的路径@javax.persistence.Version 否则创建新问题并向我们展示您的模型。
【解决方案3】:

谜团解开了。

首先-此公共服务公告。 “OptimisticLockException”是一个大桶。如果您试图追踪其中一个,请接受它可能真的是任何东西的想法。

我通过将 SQL 转储到日志并找到以下内容来解决我的问题:

update person set name='Bob' 
where id=1 and email='jj@test.com' 
and name='Robert' and password is null 
and created=2013-12-01 and deleted is null

所以我猜当你进行更新时会发生什么,它会构建一个 WHERE 子句,其中包含所有已知实体及其最初准备好的值。

这意味着,如果您的代码的任何其他部分或其他进程在您背后更改了某些内容,则此查询将失败。我错误地认为问题在于 .setName('Bob') 以某种方式更改了数据库或某些对象缓存中的名称。

真正发生的事情是 WHERE 子句包含一个日期,而我的数据库包含一个包含日期、时间和时区的完整时间戳。

目前,我只是通过注释掉模型中的时间戳来修复它,直到我弄清楚 Ebean 是否/如何处理这种数据类型。

【讨论】:

  • 谢谢!我遇到了类似的问题,原因是使用 postgres now() 函数通过手动插入设置了日期。原来 postgres 日期与 Ebean 日期的精度不同。
【解决方案4】:

我遇到了同样的问题, 经过几个小时的搜索,我找到了原因.. 这是数据库中的参数类型(在我的情况下为字符串)和我创建并尝试保存的对象不一致 -java.util.Date。

将数据库更改为保存日期时间对象后,问题解决了

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多