2017-02-07 4 views
0

Hi рассматривает следующий пример:Обновление с морфием Оптимистическая блокировка

Ресурс:

@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

Morphia уже реализует оптимистичную блокировку с помощью аннотации @Version.

http://mongodb.github.io/morphia/1.3/guides/annotations/#version

@version помечает поле в объекте контроля оптимистическую блокировку. Если версии изменятся в базе данных при изменении объекта (включая удаленные), будет выбрано исключение ConcurrentModificationException. Это поле будет автоматически управляться для вас - нет необходимости устанавливать значение, и вы не должны этого делать. Если требуется другое имя рядом с именем поля Java, имя может быть передано в эту аннотацию, чтобы изменить имя поля документа.

Я вижу, что вы уже используете аннотацию в своем примере. Убедитесь, что клиенты включают версию документа в качестве части запроса, поэтому вы также можете передать его в морфию.

Не уверен, что findAndModify сможет справиться с этим (я думаю). но, по крайней мере, я уверен saveделает обрабатывает его.

Предполагая, что объект person содержит новое имя и версию о том, что клиент смотрит, вы можете сделать прямо что-то вроде этого, чтобы обновить запись:

morphiaDataStore.save(person); 

Если был еще сохранить до этого клиент может выбрать он до версии больше не будет соответствовать и ConcurrentModificationException будет выдан с этим сообщением:

Entity of class %s (id='%s',version='%d') was concurrently updated

Смежные вопросы