Olá,
Estou desenvolvendo um projeto, mas estou com um problema na concorrência, estou utilizando o JPA Eclipselink, mas está acontecendo o seguinte:
Estou utilizando a classe abaixo para realizar alguns testes.
Estou fazendo login no sistema com 2 usuários e atualizando a mesma informação, no caso o campo “Valor”.
Busco a informação no banco de dados: vem 100.
No usuário 1, estou mudando o valor para 105 e salvando.
No usuário 2, a informação ainda é 100 e estou mudando para 110 e salvando e o JPA está permitindo que seja atualizado para 100, perdendo assim o que o usuário 1 fez.
Não está sendo disparado nenhuma PersistenceException.
Li que o JPA faz esse controle por default, mas eu tenho que adicionar alguma coisa a minha classe?
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package br.com.celg.entidade;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Rodrigo
*/
@Entity
@Table(name = "AIC")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "Aic.findAll", query = "SELECT e FROM Aic e"),
@NamedQuery(name = "Aic.findById", query = "SELECT e FROM Aic e WHERE e.codigo = :codigo"),
@NamedQuery(name = "Aic.findByOdex", query = "SELECT e FROM Aic e WHERE e.odexPk.odex = :odex"),
@NamedQuery(name = "Aic.findByValor", query = "SELECT e FROM Aic e WHERE e.valor = :valor"),
@NamedQuery(name = "Aic.findByDescricaoOdex", query = "SELECT e FROM Aic e WHERE e.descricaoOdex = :descricaoOdex"),
@NamedQuery(name = "Aic.findByInteressado", query = "SELECT e FROM Aic e WHERE e.interessado = :interessado"),
@NamedQuery(name = "Aic.findByObrasTerceiros", query = "SELECT e FROM Aic e WHERE e.obrasTerceiros = :obrasTerceiros"),
@NamedQuery(name = "Aic.findByOdi", query = "SELECT e FROM Aic e WHERE e.odi = :odi"),
@NamedQuery(name = "Aic.findByCr", query = "SELECT e FROM Aic e WHERE e.cr = :cr"),
@NamedQuery(name = "Aic.findByDataAvisoConclusao", query = "SELECT e FROM Aic e WHERE e.dataAvisoConclusao = :dataAvisoConclusao"),
@NamedQuery(name = "Aic.findByDataInicio", query = "SELECT e FROM Aic e WHERE e.dataInicio = :dataInicio"),
@NamedQuery(name = "Aic.findByDataFim", query = "SELECT e FROM Aic e WHERE e.dataFim = :dataFim"),
@NamedQuery(name = "Aic.findByStatusSgt", query = "SELECT e FROM Aic e WHERE e.statusSgt = :statusSgt"),
@NamedQuery(name = "Aic.findByStatusAvisoConclusao", query = "SELECT e FROM Aic e WHERE e.statusAvisoConclusao = :statusAvisoConclusao"),
@NamedQuery(name = "Aic.findByDataEnergizacao", query = "SELECT e FROM Aic e WHERE e.dataEnergizacao = :dataEnergizacao"),
@NamedQuery(name = "Aic.findByRegional", query = "SELECT e FROM Aic e WHERE e.regional = :regional"),
@NamedQuery(name = "Aic.findByResponsavel", query = "SELECT e FROM Aic e WHERE e.responsavel = :responsavel"),
@NamedQuery(name = "Aic.findByMunicipio", query = "SELECT e FROM Aic e WHERE e.municipio = :municipio")})
public class Aic extends SuperLogic implements Serializable {
private static final long serialVersionUID = 1L;
// @Max(value=?) @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
@Column(name="DATA")
@Temporal(TemporalType.TIMESTAMP)
private Date data;
@javax.persistence.Transient
private String odex;
@Column(name = "VALOR")
private BigDecimal valor;
@Column(name = "DESCRICAO_ODEX")
private String descricaoOdex;
@Column(name = "INTERESSADO")
private String interessado;
@Column(name = "OBRAS_TERCEIROS")
private String obrasTerceiros;
@Column(name = "ODI")
private Long odi;
@Column(name = "DATA_AVISO_CONCLUSAO")
@Temporal(TemporalType.TIMESTAMP)
private Date dataAvisoConclusao;
@Column(name = "DATA_INICIO")
@Temporal(TemporalType.TIMESTAMP)
private Date dataInicio;
@Column(name = "DATA_FIM")
@Temporal(TemporalType.TIMESTAMP)
private Date dataFim;
@Column(name = "MUNICIPIO")
private String municipio;
@Column(name = "REGIONAL")
private String regional;
@Column(name = "RESPONSAVEL")
private String responsavel;
@Column(name = "STATUS_SGT")
private String statusSgt;
@Column(name = "STATUS_AVISO_CONCLUSAO")
private String statusAvisoConclusao;
@Column(name = "DATA_ENERGIZACAO")
@Temporal(TemporalType.TIMESTAMP)
private Date dataEnergizacao;
@Column(name = "DATA_REF")
private String dataRef;
@JoinColumn(name = "ODEX_PK", referencedColumnName = "CODIGO")
@ManyToOne(cascade = CascadeType.ALL)
private Odex odexPk;
@JoinColumn(name = "CR", referencedColumnName = "CODIGO")
@ManyToOne
private Cr cr;
@javax.persistence.Transient
private ClassTaxonomia idClassTaxonomia;
public Aic() {
}
public Date getData() {
return data;
}
public void setData(Date data) {
this.data = data;
}
public String getOdex() {
return odex;
}
public void setOdex(String odex) {
this.odex = odex;
}
public BigDecimal getValor() {
return valor;
}
public void setValor(BigDecimal valor) {
this.valor = valor;
}
public String getDescricaoOdex() {
return descricaoOdex;
}
public void setDescricaoOdex(String descricaoOdex) {
this.descricaoOdex = descricaoOdex;
}
public String getInteressado() {
return interessado;
}
public void setInteressado(String interessado) {
this.interessado = interessado;
}
public String getObrasTerceiros() {
return obrasTerceiros;
}
public void setObrasTerceiros(String obrasTerceiros) {
this.obrasTerceiros = obrasTerceiros;
}
public Long getOdi() {
return odi;
}
public void setOdi(Long odi) {
this.odi = odi;
}
public Date getDataAvisoConclusao() {
return dataAvisoConclusao;
}
public void setDataAvisoConclusao(Date dataAvisoConclusao) {
this.dataAvisoConclusao = dataAvisoConclusao;
}
public Date getDataInicio() {
return dataInicio;
}
public void setDataInicio(Date dataInicio) {
this.dataInicio = dataInicio;
}
public Date getDataFim() {
return dataFim;
}
public void setDataFim(Date dataFim) {
this.dataFim = dataFim;
}
public String getMunicipio() {
return municipio;
}
public void setMunicipio(String municipio) {
this.municipio = municipio;
}
public String getRegional() {
return regional;
}
public void setRegional(String regional) {
this.regional = regional;
}
public String getResponsavel() {
return responsavel;
}
public void setResponsavel(String responsavel) {
this.responsavel = responsavel;
}
public String getStatusSgt() {
return statusSgt;
}
public void setStatusSgt(String statusSgt) {
this.statusSgt = statusSgt;
}
public String getStatusAvisoConclusao() {
return statusAvisoConclusao;
}
public void setStatusAvisoConclusao(String statusAvisoConclusao) {
this.statusAvisoConclusao = statusAvisoConclusao;
}
public Date getDataEnergizacao() {
return dataEnergizacao;
}
public void setDataEnergizacao(Date dataEnergizacao) {
this.dataEnergizacao = dataEnergizacao;
}
public String getDataRef() {
return dataRef;
}
public void setDataRef(String dataRef) {
this.dataRef = dataRef;
}
public Odex getOdexPk() {
return odexPk;
}
public void setOdexPk(Odex odexPk) {
this.odexPk = odexPk;
}
public Cr getCr() {
return cr;
}
public void setCr(Cr cr) {
this.cr = cr;
}
public ClassTaxonomia getIdClassTaxonomia() {
return idClassTaxonomia;
}
public void setIdClassTaxonomia(ClassTaxonomia idClassTaxonomia) {
this.idClassTaxonomia = idClassTaxonomia;
}
@Override
public int hashCode() {
int hash = 0;
hash += (getCodigo() != null ? getCodigo().hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Aic)) {
return false;
}
Aic other = (Aic) object;
if ((this.getCodigo() == null && other.getCodigo() != null) || (this.getCodigo() != null && !this.getCodigo().equals(other.getCodigo()))) {
return false;
}
return true;
}
@Override
public String toString() {
return "br.com.celg.entidade.Aic[ codigo=" + getCodigo() + " ]";
}
}