嗨,考虑到下面的例子:
资源:
@PUT
@Path("{id}")
public Response update(@PathParam(value = "id") final String id, final Person person) {
final Person person = service.getPerson(id);
final EntityTag etag = new EntityTag(Integer.toString(person.hashCode()));
// If-Match is required
ResponseBuilder builder = request.evaluatePreconditions(etag);
if (builder != null) {
throw new DataHasChangedException("Person data has changed: " + id);
}
service.updatePerson(id, person.getName());
....
}服务:
public void updatePerson(final String id, final String name) {
final Query<Person> findQuery = morphiaDataStore.createQuery(Person.class).filter("id ==", id);
UpdateOperations<Person> operation = morphiaDataStore.createUpdateOperations(Person.class).set("name", name);
morphiaDataStore.findAndModify(findQuery, operation );
}人:
@Entity("person")
public class Person {
@Id
private ObjectId id;
@Version
private Long version;
private String name;
...
}我确实检查提供的etag是否与数据库中的人相同。但是,此检查是对资源本身执行的。我不认为这是安全的,因为更新发生在检查之后,同时另一个线程可能会抛出检查。如何才能正确解决这一问题?如有任何例子或建议,我们将不胜感激。
发布于 2017-07-28 21:54:28
摩尔菲亚已经通过@Version注释实现了乐观锁定。
http://mongodb.github.io/morphia/1.3/guides/annotations/#version
@Version在实体中标记一个字段以控制乐观锁定。如果在修改实体(包括删除)时数据库中的版本发生变化,则将引发ConcurrentModificationException。该字段将自动为您管理-没有必要设置值,您不应该这样做。如果需要Java字段名旁边的另一个名称,则可以向该注释传递一个名称以更改文档的字段名。
我看到您已经在示例中使用了注释。请确保客户端将文档的版本作为请求的一部分,这样您也可以将其传递给morphia。
不确定findAndModify是否能够处理它(我认为它能够)。但至少我确信save确实能处理这件事。
假设对象person包含客户端正在查看的新名称和版本,您可以直接执行类似的操作来更新记录:
morphiaDataStore.save(person);如果在此客户端获取之前还有另一个保存,则版本将不再匹配,并将发出带有以下消息的ConcurrentModificationException:
Entity of class %s (id='%s',version='%d') was concurrently updated
https://stackoverflow.com/questions/42094242
复制相似问题