使用Morphia乐观锁定进行更新

时间:2017-02-07 15:52:47

标签: java mongodb concurrency morphia optimistic-locking

嗨,请考虑以下示例:

资源:

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

1 个答案:

答案 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