我有一个使用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中看到了类似的逻辑。另外,我应该能够看到绑定变量的值吗?
UPDATE:我从控制器内部调用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");
}
答案 0 :(得分:15)
我有另一种方法,我在其中添加注释
@EntityConcurrencyMode(ConcurrencyMode.NONE)
到实体类。
这会禁用乐观锁定并发修改检查,这意味着SQL变为
update person set name=? where id=?
这更加乐观,因为它只是覆盖了任何中间变化。
答案 1 :(得分:8)
有点晚了,但对于你的案例@Version
,注释应该是解决方案。我们主要使用它java.util.Date
,所以它也可以用于确定上次记录更新的日期,在Play模型中只是:
@Version
public java.util.Date version;
在这种情况下,更新语句将仅使用id
和version
字段完成 - 尤其适用于使用大型模型时:
update person set name='Bob'
where id=1 and version='2014-03-03 22:07:35';
注意:您不需要/应该在每次保存时手动更新此字段,Ebean会自行完成。 version
值仅在有更新数据时更改(因此使用obj.update()
,其中没有任何更改不会更新version
字段)
答案 2 :(得分:4)
神秘解决了。
首先是这个公共服务公告。 “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')更改了DB或某个对象缓存中的名称。
真正发生的事情是WHERE子句包含一个日期,而我的数据库包含一个包含日期,时间和时区的整个时间戳。
目前,我只是通过注释模型中的时间戳来修复它,直到我能够确定Ebean是否/如何处理这种数据类型。
答案 3 :(得分:0)
我有同样的问题, 经过几个小时的搜索我找到了原因.. 它是数据库中的参数类型(在我的情况下是字符串)和我创建并尝试保存-java.util.Date的对象的不一致。
更改数据库以保存datetime对象后问题得以解决