Tratando Violação de Restrição de Integridade

9 respostas
V

Olá senhores, tudo bem?!
Estou iniciando em JSF e Hibernate e estou tomando um coro em certos aspectos.

Como eu trato a exceção de violão de restrição de integridade em um delete por exemplo?
Estou tratando a exceção como uma ConstraintViolationException. Funciona, eu exibo a mensagem que o registro não pode excluído, mas mesmo assim ela continua explodindo no Trace do Eclipse!

GRAVE: Cannot delete or update a parent row: a foreign key constraint fails (`scp`.`veiculos`, CONSTRAINT `FK7976D244CB63E872` FOREIGN KEY (`Obras_idObra`) REFERENCES `obras` (`idObra`))
26/10/2012 17:31:12 org.hibernate.event.def.AbstractFlushingEventListener performExecutions
GRAVE: Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
	at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:92)
	at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:87)
	at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:222)
	at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2479)
	at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2697)
	at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:74)
	at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:146)
	at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
	at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
	at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
	at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
	at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
	at dao.ObraDaoImp.remove(ObraDaoImp.java:46)
	at controller.ObraController.excluirObra(ObraController.java:122)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.apache.el.parser.AstValue.invoke(AstValue.java:278)
	at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:274)
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:102)
	at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:144)
	at javax.faces.event.ActionEvent.processListener(ActionEvent.java:84)
	at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:773)
	at javax.faces.component.UICommand.broadcast(UICommand.java:296)
	at javax.faces.component.UIData.broadcast(UIData.java:912)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:781)
	at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:922)
	at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:74)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:114)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:308)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`scp`.`veiculos`, CONSTRAINT `FK7976D244CB63E872` FOREIGN KEY (`Obras_idObra`) REFERENCES `obras` (`idObra`))
	at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1666)
	at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1082)
	at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
	... 50 more
No meu DAO
package dao;

import java.util.List;

import model.Obra;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.exception.ConstraintViolationException;

import util.HibernateUtil;
import exceptions.ViolacaoDeIntegridade;

public class ObraDaoImp implements ObraDao{

	@Override
	public void save(Obra obra) {
		Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction t = session.beginTransaction();
        session.saveOrUpdate(obra);
        t.commit();		
        session.close();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Obra> list() {
		Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction t = session.beginTransaction();
        List<Obra> lista = session.createQuery("from Obra").list();
        t.commit();
        session.close();
        return lista;
	}

	@Override
	public Obra getObra(Integer idObra) {
		Session session = HibernateUtil.getSessionFactory().openSession();
		Obra obra = (Obra) session.load(Obra.class, idObra);				
        return obra;
        
	}

	@Override
	public void remove(Obra obra) throws ViolacaoDeIntegridade{
		Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction t = session.beginTransaction();
		try{			
	        session.delete(obra);
	        t.commit();	    	
		}catch (ConstraintViolationException e) {			
			t.rollback();
			throw new ViolacaoDeIntegridade("Violação de Restrição de Integridade!");
		}
		finally{
			session.close();
		}
		
		
		
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Obra> searchByDescricao(String descricao) {
		Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction t = session.beginTransaction();        
		List<Obra> lista = session.createQuery("from Obra o " +        		
        		"where lower(o.descricao) like lower(:descricao)")
        		.setParameter("descricao", "%"+descricao+"%")
        		.list();
        t.commit();
        return lista;
	}

}
No meu Controller
package controller;

import java.io.Serializable;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

import model.Municipio;
import model.Obra;
import model.UF;
import util.MyListDataModel;
import dao.MunicipioDaoImp;
import dao.ObraDao;
import dao.ObraDaoImp;
import dao.UFDaoImp;
import exceptions.ViolacaoDeIntegridade;

@ManagedBean
@ViewScoped
public class ObraController implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Obra obra;
	private DataModel<Obra> listaObras;
	private Obra obraTemp;
	private String pesquisa = null;
	
	private Municipio municipio;	
	private UF uf;
	private List<Municipio> listaMunicipios;	
	private List<UF> listaUFs;
		
	@PostConstruct
	public void init(){
		listaUFs = new UFDaoImp().list();		
	}
	
	public void atualizaMunicipio(AjaxBehaviorEvent event){		
		listaMunicipios = new MunicipioDaoImp().list(uf);		
	}
	public Municipio getMunicipio() {
		return municipio;
	}
	public void setMunicipio(Municipio municipio) {
		this.municipio = municipio;
	}
	public UF getUf() {
		return uf;
	}
	public void setUf(UF uf) {
		this.uf = uf;
	}
	public List<Municipio> getListaMunicipios() {
		return listaMunicipios;
	}
	public void setListaMunicipios(List<Municipio> listaMunicipios) {
		this.listaMunicipios = listaMunicipios;
	}
	public List<UF> getListaUFs() {		
		return listaUFs;
	}
	public void setListaUFs(List<UF> listaUFs) {
		this.listaUFs = listaUFs;
	}	
	
	public ObraController(){
		this.obra = new Obra();
	}

	public DataModel<Obra> getListaObras() {
		return listaObras;
	}

	public DataModel<Obra> getListaByDescricao(ActionEvent actionEvent) {
		
		List<Obra> lista = new ObraDaoImp().searchByDescricao(this.pesquisa);		
		listaObras = new MyListDataModel<Obra>(lista);	
		return listaObras;
	}

	public String getPesquisa() {
		return pesquisa;
	}

	public void setPesquisa(String pesquisa) {
		this.pesquisa = pesquisa;
	}

	public Obra getObra() {
		return obra;
	}

	public void setObra(Obra obra) {
		this.obra = obra;
	}
	
	public void prepararAdicionarObra(ActionEvent actionEvent) {		
		this.obra = new Obra();
		this.uf=null;
	}
	
	public void prepararAlterarObra(ActionEvent actionEvent) {
		this.obra = (Obra) (listaObras.getRowData());		
		this.uf = obra.getMunicipio().getUf();
		listaMunicipios = new MunicipioDaoImp().list(obra.getMunicipio().getUf());	
		
	}
	
	public void prepararExcluirObra(ActionEvent actionEvent){	
		this.obraTemp =  (Obra) (listaObras.getRowData());		
	}

	public void excluirObra(ActionEvent actionEvent) {
		try{
			ObraDao obraDao = new ObraDaoImp();		
			obraDao.remove(this.obraTemp);		
			List<Obra> lista = new ObraDaoImp().searchByDescricao(this.pesquisa);
			listaObras = new ListDataModel<Obra>(lista);			
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,"Registro Excluído com Sucesso!","Registro Excluído com Sucesso!"));
		}catch (ViolacaoDeIntegridade e) {					
				FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,"Não é possível excluir este registro!","Não é possível excluir este registro!"));
			
		}				
	}

	public void salvarObra(ActionEvent actionEvent) {
		ObraDao obraDao = new ObraDaoImp();
		obraDao.save(this.obra);
		this.obra = new Obra();		
		this.uf=null;
		FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Registro Salvo com Sucesso!","Registro Salvo com Sucesso!"));		
	}
	
	
	

}
Modelo
package model;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="obras")
public class Obra implements Serializable{
	
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private Integer idObra;
	
	
	@JoinColumn(name = "Municipios_idMunicipio")
	private Municipio municipio;
	
	@Column(length=255)
	private String descricao;
	
	public Integer getIdObra() {
		return idObra;
	}
	public void setIdObra(Integer idObra) {
		this.idObra = idObra;
	}
	public Municipio getMunicipio() {
		return municipio;
	}
	public void setMunicipio(Municipio municipio) {
		this.municipio = municipio;
	}
	public String getDescricao() {
		return descricao;
	}
	public void setDescricao(String descricao) {
		this.descricao = descricao;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((descricao == null) ? 0 : descricao.hashCode());
		result = prime * result + ((idObra == null) ? 0 : idObra.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Obra other = (Obra) obj;
		if (descricao == null) {
			if (other.descricao != null)
				return false;
		} else if (!descricao.equals(other.descricao))
			return false;
		if (idObra == null) {
			if (other.idObra != null)
				return false;
		} else if (!idObra.equals(other.idObra))
			return false;
		return true;
	}	
	
	
	
}
Ele não deixa apagar o registro porque há uma restrição de integridade na classe veículo.
package model;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="veiculos")
public class Veiculo implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private Integer idVeiculo;
	
	@ManyToOne
	@JoinColumn(name = "TiposVeiculo_idTipoVeiculo")
	private TipoVeiculo tipoVeiculo;
	
	@ManyToOne 
	@JoinColumn(name = "Obras_idObra")
	private Obra obra;
	
	private String placa;
	
	private String descricao;

	public Integer getIdVeiculo() {
		return idVeiculo;
	}

	public void setIdVeiculo(Integer idVeiculo) {
		this.idVeiculo = idVeiculo;
	}

	public TipoVeiculo getTipoVeiculo() {
		return tipoVeiculo;
	}

	public void setTipoVeiculo(TipoVeiculo tipoVeiculo) {
		this.tipoVeiculo = tipoVeiculo;
	}

	public Obra getObra() {
		return obra;
	}

	public void setObra(Obra obra) {
		this.obra = obra;
	}

	public String getPlaca() {
		return placa;
	}

	public void setPlaca(String placa) {
		this.placa = placa;
	}

	public String getDescricao() {
		return descricao;
	}

	public void setDescricao(String descricao) {
		this.descricao = descricao;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((descricao == null) ? 0 : descricao.hashCode());
		result = prime * result
				+ ((idVeiculo == null) ? 0 : idVeiculo.hashCode());
		result = prime * result + ((placa == null) ? 0 : placa.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Veiculo other = (Veiculo) obj;
		if (descricao == null) {
			if (other.descricao != null)
				return false;
		} else if (!descricao.equals(other.descricao))
			return false;
		if (idVeiculo == null) {
			if (other.idVeiculo != null)
				return false;
		} else if (!idVeiculo.equals(other.idVeiculo))
			return false;
		if (placa == null) {
			if (other.placa != null)
				return false;
		} else if (!placa.equals(other.placa))
			return false;
		return true;
	}
	

}

9 Respostas

Hebert_Coelho

As vezes a exception é camuflada: java.sql.BatchUpdateException. Você pode tentar descobrir o tempo que está chegando capturando por (Exception ex) e vendo de qual tipo ela é.

O que você poderia fazer é if(!departamento.getCarros().isEmpty()) throws ExisteCarrosException.

Realmente capturar qual é a dependÊncia é muito chato. Até.

V

Hebert, obrigado pela ajuda!

Andei testando aqui na aplicação e realmente a exceção é do tipo ConstraintViolationException.
A minha pergunta é, porque mesmo assim, eu pegando ela com o catch, ela cai na stacktrace ?

Não anotei nos meus relacionamentos nenhuma opção de cascade, porque na maioria deles são RESTRICT no delete.

Hebert_Coelho

VagnerMG:
Hebert, obrigado pela ajuda!

Andei testando aqui na aplicação e realmente a exceção é do tipo ConstraintViolationException.
A minha pergunta é, porque mesmo assim, eu pegando ela com o catch, ela cai na stacktrace ?

Não anotei nos meus relacionamentos nenhuma opção de cascade, porque na maioria deles são RESTRICT no delete.

Tente fazer um rollback no catch.

V

Hebert Coelho:
VagnerMG:
Hebert, obrigado pela ajuda!

Andei testando aqui na aplicação e realmente a exceção é do tipo ConstraintViolationException.
A minha pergunta é, porque mesmo assim, eu pegando ela com o catch, ela cai na stacktrace ?

Não anotei nos meus relacionamentos nenhuma opção de cascade, porque na maioria deles são RESTRICT no delete.

Tente fazer um rollback no catch.

Rapaz, mesmo com o Rollback a exceção continua explodino no stacktrace!
Não sei o que mais fazer!

Hebert_Coelho

VagnerMG:
Hebert Coelho:
VagnerMG:
Hebert, obrigado pela ajuda!

Andei testando aqui na aplicação e realmente a exceção é do tipo ConstraintViolationException.
A minha pergunta é, porque mesmo assim, eu pegando ela com o catch, ela cai na stacktrace ?

Não anotei nos meus relacionamentos nenhuma opção de cascade, porque na maioria deles são RESTRICT no delete.

Tente fazer um rollback no catch.

Rapaz, mesmo com o Rollback a exceção continua explodino no stacktrace!
Não sei o que mais fazer!

No catch tenta jogar uma expcetion sua. Realmente tá estranho! O.o

V

Mesmo alterando o catch para pegar Exception ao invés de ConstraintViolationException, a exceção é lançada no stacktrace!

Isso é comportamento do Hibernate? ele sempre vai imprimir a stacktrace?
Minha preocupação é se a exceção está chegando na JVM!

Hebert_Coelho

VagnerMG:
Mesmo alterando o catch para pegar Exception ao invés de ConstraintViolationException, a exceção é lançada no stacktrace!

Isso é comportamento do Hibernate? ele sempre vai imprimir a stacktrace?
Minha preocupação é se a exceção está chegando na JVM!

Eu digo você criar a sua exception. MeuErro extends Exception. Você daria catch e jogar a do hibernate.

Outra coisa que vc poderia fazer é controlar o nivel de log co o log4j.

Aqui mostra como fazer: JPA Consultas e Dicas.

V

Já tentei fazer isso Hebert!
Vou atualizar o post inicial com toda minha classe! Talvez ajude!

V

@Override public void remove(Obra obra) throws ViolacaoDeIntegridade{ Session session = HibernateUtil.getSessionFactory().openSession(); Transaction t = session.beginTransaction(); try{ Query query = session.createQuery("delete Obra o" + " where o.idObra = :idObra") .setParameter("idObra",obra.getIdObra()); query.executeUpdate(); t.commit(); }catch (ConstraintViolationException e) { t.rollback(); throw e; } finally{ session.close(); } }

Hebert, consegui resolvendo usando query ao invés do delete!
Desta forma a exceção não foi lançada no stacktrace!

Criado 26 de outubro de 2012
Ultima resposta 29 de out. de 2012
Respostas 9
Participantes 2