Optimistic locking in a RESTful application

后端 未结 2 998
隐瞒了意图╮
隐瞒了意图╮ 2020-12-31 17:09

At work, we\'re developing a RESTful application where the data layer will be handled by Hibernate. But we\'re not sure how to handle updates on entities.

We\'re pla

相关标签:
2条回答
  • 2020-12-31 17:18

    Your strategy is good. Simply copy the version number coming from the client into the loaded entity (or use merge(), which will do the same), and when Hibernate flushes the entity, if the version number has been incremented, you'll have an optimistic lock exception.

    You don't need to check anything by yourself. Hibernate does the check for you.

    0 讨论(0)
  • 2020-12-31 17:37

    The alternative to checking the version yourself is to just construct the entity object and invoke entityManager.merge which should also trigger optimistic lock exceptions if the version changed in the meantime, but it's won't throw if the object was deleted in the meantime. To handle that properly, you will have to check it yourself.

    Instead of implementing this by loading entity state separately, you could make use of Blaze-Persistence Updatable Entity Views which is a library for developing DTOs on top of JPA that also implements support for optimistic locking. Your use case should be supported already, though I don't have a very good integration for Spring WebMvc yet, so you will have to do some plumbing yourself for now. I have something in mind for this though, it's just a matter of time and interested parties until the integration will be smoother.

    Updatable entity views allow to map a subset of entities and also only flush that subset back. Thanks to the use of dirty tracking, it knows exactly what changed, allowing for fine grained flushing.

    So the idea for PATCH support, which seems to be what you want here, is to just get an empty reference by id for an object. Being empty means, that it has no data i.e. all null values. The dirty tracking assumes the initial state is all null then. You can simply map a request payload onto this object, if a value is null, it won't recognize it as being changed, thus ignore it. If anything non-null was set, it determines that such a field is dirty and on flush, only flushes dirty values.

    I haven't tried it myself yet, but you could do something like this

    // Create reference for the id, the object is empty i.e. all null except for the id
    CustomerDTO dto = entityViewManager.getReference(CustomerDTO.class, someId);
    // Map the payload on the DTO which will call setFoo(null) but that's ok, because that isn't considered being dirty
    jsonMapper.map(requestPayload, dto);
    // Flush dirty changes i.e. non-null values
    entityViewManager.update(entityManager, dto);
    

    The executed update query when using the PARTIAL flush mode will only contain set clauses for properties with non-null values. The DTO would look like this

    @EntityView(Customer.class)
    @UpdatableEntityView(mode = FlushMode.PARTIAL)
    public interface CustomerDTO {
      @IdMapping Integer getId();
      String getName();
      void setName(String name);
      String getDesc();
      void setDesc(String desc);
    }
    

    If nothing is dirty, it won't even execute a query.

    0 讨论(0)
提交回复
热议问题