java – Optimistic lock; why doesn't it throw an exception?

Question:

I tried to simulate an optimistic Lock situation where you try to update the same record twice, but the exception is not triggered.

I find it interesting that even after changing the holder value and giving a MERGE, the version value is not updated in the object or in the base record.

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("financas");
    EntityManager em1 = emf.createEntityManager();
    EntityManager em2 = emf.createEntityManager();

    em1.getTransaction().begin();
    em2.getTransaction().begin();

    Conta c1 = em1.find(Conta.class,1);
    em1.lock(c1, LockModeType.OPTIMISTIC);
    em1.merge(c1);
    em1.getTransaction().commit();
    Conta c2 = em2.find(Conta.class,1);
    em2.lock(c2, LockModeType.OPTIMISTIC);
    em2.merge(c2);
    em2.getTransaction().commit();

————- UPDATED ———————

Class content counts:

package br.com.financas.modelo;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Version;

@Entity
public class Conta {

    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String titular;
    private String banco;
    private String agencia;
    private String numero;

    @Version
    private int versao;

    public int getVersao() {
        return versao;
    }
    public void setVersao(int versao) {
        this.versao = versao;
    }
    @OneToMany(mappedBy="conta")
    private List<Movimentacao> movimentacoes;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getTitular() {
        return titular;
    }
    public void setTitular(String titular) {
        this.titular = titular;
    }
    public String getBanco() {
        return banco;
    }
    public void setBanco(String banco) {
        this.banco = banco;
    }
    public String getAgencia() {
        return agencia;
    }
    public void setAgencia(String agencia) {
        this.agencia = agencia;
    }
    public String getNumero() {
        return numero;
    }
    public void setNumero(String numero) {
        this.numero = numero;
    }
    public List<Movimentacao> getMovimentacoes() {
        return movimentacoes;
    }
    public void setMovimentacoes(List<Movimentacao> movimentacoes) {
        this.movimentacoes = movimentacoes;
    }


}

Why is the exception not thrown?

Answer:

The exception is not thrown for two reasons:

1) No changes were made to the entity in either the first or the second context in which it was obtained and persisted, so there is no way for there to be a conflict in the second context.

2) The transaction from the first context was completed ( committed ) before the entity was obtained from the second context. So even if there was no problem 1 , there would still be no exception because between getting and persisting the entity in the second context no changes were made in another context.

In order for there to be an exception, the code needs to look something like this:

Conta c1 = em1.find(Conta.class,1);
em1.lock(c1, LockModeType.OPTIMISTIC);
c1.setNumero(novoNumero);       // linha adicionada
em1.merge(c1);
//em1.getTransaction().commit();   linha removida
Conta c2 = em2.find(Conta.class,1);
em2.lock(c2, LockModeType.OPTIMISTIC);
em1.getTransaction().commit();  // linha adicionada
c2.setNumero(aindaOutroNumero); // linha adicionada
em2.merge(c2);
em2.getTransaction().commit();

In the code above, the version column has been updated and persisted after the entity is retrieved from another context. So when the entity is finally persisted in the other context, the version value found in the base is different from the one in the entity in memory, which will throw an exception of "the record was changed by another user" .

Scroll to Top