嗨,请考虑以下示例:
资源:
@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是否与数据库中的人员相同。但是,此检查已在资源本身上完成。我不认为这是安全的,因为更新发生在检查之后,另一个线程可能在此期间抛出了支票。如何才能正确解决?任何例子或建议都表示赞赏。
答案 0 :(得分:0)
Morphia已经通过@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