Pesquisando na internet, esse erro ocorre em duas situações diferentes:
1 - Quando você tentar fazer uma operação de escrita em um registro da qual o hibernate não se tem mais a instãncia.
2 - Quando dois ou mais acessos (threads) implicam na alteração de um mesmo registro.
O Erro gerado é um StaleStateException:
No exemplo que usei que provocou o erro, foi mapeado uma entidade JPA de nome Funcionalidade, ela tem um auto-mapeamento permitindo ser exibida em uma camada view da forma hierárquica (a exemplo de uma treeview), ou seja, uma funcionalidade pode apontar para outra, uma se torna pai de várias funcionalidades filhas.
Vejam a entidade Funcionalidade.java:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "FNC_ID", insertable = false, updatable = false)
private Long id;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity = Aplicacao.class)
@JoinColumn(name = "FNC_APL_ID")
Aplicacao aplicacao;
@Column(name = "FNC_SG", nullable = false)
private String sigla;
@Column(name = "FNC_NM", nullable = false)
private String nome;
@Column(name = "FNC_DS")
private String descricao;
@Column(name = "FNC_DH_ATUALIZACAO", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date atualizacao;
@Column(name = "FNC_USR_ID", nullable = false)
private Long usuarioAtualizacao;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity = SituacaoRegistro.class)
@JoinColumn(name = "FNC_SRG_ID", nullable = false)
SituacaoRegistro situacaoRegistro;
@ManyToOne
@JoinColumn(name = "FNC_FNC_ID", referencedColumnName="FNC_ID")
Funcionalidade pai;
@Column(name = "FNC_CM_HIERARQUIA", nullable = false)
private String codigoHierarquia;
Na parte relacionada ao @ManyToOne de Funcionalidade pai eu fiz dessas duas formas diferentes:
Mas tanto mapeando de uma forma, como de outra, o erro ocorre.
O erro ocorre quando tento atualizar uma funcinalidade existente atribuíndo a ela uma outra funcionalidade (ou seja, ela se tornará filha de outra). Se eu tentar alterar qualquer outro atributo (menos o do relacionamento) ela persiste com sucesso no banco. O código testado é o seguinte:
//acha a funcionalidade
Funcionalidade lFunc = (Funcionalidade)
JPAUtilSCR.getInstancia().find(Funcionalidade.class, 1374l);
//acha a funcionalidade que será a pai
Funcionalidade lPai = (Funcionalidade)
JPAUtilSCR.getInstancia().find(Funcionalidade.class, 1266l);
//adiciona um pai à funcionalidade
lFunc.setPai(lPai);
FuncionalidadeBS.getInstancia().persistir(lFunc);
//commit
JPAUtilSCR.getInstancia().commitTran();
Como eu disse, se tentar alterar qualquer outro atributo, o registro é atualizado com sucesso, porém no caso de tentar associar um pai, ele simplesmente não vai.