Tratando modificações simultâneas com Spring
Tags: java, spring, locks
Published: 2020-05-21 19:22:19


Neste artigo vamos entender como tratar modificações realizadas por usuários que se sobrescrevem, e como resolver este problema com o Spring. 

### O problema

Tendo como base a classe Note, vamos imaginar o seguinte cenário:

```java
public class Note {
    private String title;
    private String body;
    // getters & setters...
}
```

1. O ``usuário 1`` abre a tela e modifica o campo ``título``
2. O ``usuário 2`` abre a tela e modifica o campo ``corpo``
3. O ``usuário 1`` atualiza as informações com o ``título``
4. O ``usuário 2`` sobrescreve as informações do ``usuário 1``, já que este foi o último a realizar a alteração
5. O registro fica apenas com o **corpo alterado**

Desta forma, temos um problema gerado pela falta de um lock.

### E o que são locks?

Lock é uma maneira de evitar que mais de um acesso seja realizado à um determinado recurso. Por exemplo: em um banco de dados, se você gerar um update e esquecer de dar o commit, será criado um bloqueio (lock), para que os consumidores, tenham sempre a versão mais atualizada do dado.

Este exemplo é o que chamamos de lock pessimista (pessimistic lock).

### lock pessimista

O lock pessimista é quando você 'segura' o recurso (exemplo citado acima), para que ninguém consiga utilizar enquanto se está trabalhando com a mesma. Isso pode causar um problema na experiência do usuário, já que somente a pessoa que 'pegou primeiro', poderá trabalhar com este recurso, enquanto isso, o outro usuário ficará aguardando, dando uma péssima impressão de que seu software está lento, ou até travou 😱 (Em alguns casos pode gerar até um [deadlock](https://pt.wikipedia.org/wiki/Deadlock). 


### O lock otimista

> Apesar de conter *lock* no nome, neste cenário não existe algo segurando o recurso.

No lock otimista, fazemos uma checagem no registro antes de atualizar. Este controle pode ser feito por data, sequencial ou de outras formas mais criativas.

Seguindo um exemplo de lock otimista:

1. O ``usuário 1`` abre a tela (com a versão 1) e modifica o campo ``title``;
2. O ``usuário 2`` abre a tela (com a versão 1) e modifica o campo ``body``;
3. O ``usuário 1`` atualiza as informações com o ``title``;
4. O app internamente atualiza o campo de versão para 2;
5. O ``usuário 2`` tenta enviar a informação do corpo modificado, porém com a ``versão 1``;
5. O lock é realizado e conseguimos detectar que alguém atualizou para outra versão anteriormente 🤗.

### Colocando em prática

``` java
public class Note {

    private String title;
    private String body;

    // Atributo que fará a verificação se
    // a versão atual é a mais recente
    @Version
    private int version;
}
```

Com a classe Note em mãos, adicionei um atributo int na classe Note, com o annotation ``@Version``. Dessa forma, o Spring automaticamente realiza as checagens necessárias, e sempre que o registro for atualizado, a versão será incrementada.

### Conclusão

Existem diversas formas de tratar modificações simultâneas, o Spring nos entrega o ``@Version``, que de forma simples e prática, nos permite realizar um controle sobre as versões de um determinado registro.

E você, já pesquisou no seu framework favorito como resolver esse tipo de problema?