Tratar Exceptions do Hibernate em JPA

7 respostas
J

Olá, gostaria de saber se é possivel desenvolver uma classe onde eu possa tratar as exceptions do hibernate, pois pelo que pude perceber o JPA trata as exceptions de modo generico e desta forma não consigo ter acesso a informações como o codigo do erro no banco de dados. Sei que desta forma uma parte do meu codigo ficará atrelada ao hibernate mais não vejo outra saida, preciso mostrar mensagens objetivas e amigaveis ao usuario! Alguem pode me ajudar?

grato!

msn: [email removido]

7 Respostas

B

Amigo, sempre que uma Exception é lançada você pode ver a causa.
Geralmente na causa está a Exception JDBC pura que geralmente é um SqlException pra o caso de consultas.

Se o tipo da causa for uma SqlException você pode pegar o código do erro.

Algo mais ou menos assim

cach (SqlException e) {
  e.getErrorCode()
cach (Exception e) {
  if (e.getCause() != null && e.getCause() instanceof SqlException) {
    ((SqlException)e.getCause()).getErrorCode()
  }
}

A idéia é mais ou menos essa

J

Pois eh black_fire, eu não estou conseguindo chegar ate a SQLException usando o JPA/Hibernate. A minha situação é a seguinte: Segue os metodos abaixo.

//Metodo Salvar da Classe Cadastro de Bairro public void Salvar() { try { beanBairro = new Bairro(); beanBairro.setBaiDescricao(jtfBairro.getText()); //chama o metodo salvar da classe Conexao e passa como parametro o objeto bairro populado Conexao.Salvar(beanBairro); } catch (Exception e) { //Local onde eu mostro o erro capturado do metodo salvar da classe Conexao atravez do comando //e.getMessage() JOptionPane.showMessageDialog(null, e.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE); } }

//Metodo salvar da Classe Conexao public static void Salvar(Object objeto) throws EntityExistsException, IllegalStateException, IllegalArgumentException, TransactionRequiredException, Exception { EntityManager manager = null; try { manager = Conexao.getConexao(); manager.getTransaction().begin(); manager.persist(objeto); manager.getTransaction().commit(); JOptionPane.showMessageDialog(null, "Salvo com sucesso", "", JOptionPane.PLAIN_MESSAGE); } catch (EntityExistsException eee) { manager.getTransaction().rollback(); throw new EntityExistsException("Operação não realizada, tentativa de duplicidade de registros \n" + eee); } catch (IllegalStateException ise) { manager.getTransaction().rollback(); throw new IllegalStateException("operação não realizada \n" + "Erro exception number 2 - IllegalStateException"); } catch (IllegalArgumentException iae) { manager.getTransaction().rollback(); throw new IllegalArgumentException("operação não realizada \n" + "Erro exception number 3 - IllegalArgumentException"); } catch (TransactionRequiredException tre) { manager.getTransaction().rollback(); throw new TransactionRequiredException("operação não realizada \n" + "Erro exception number 4 - TransactionRequiredException"); } catch (Exception e) { manager.getTransaction().rollback(); throw new Exception("operação não realizada \n" + "Erro exception number 4 - TransactionRequiredException"); } }
Os metodos funcionam perfeitamente o meu problema se resume no seguinte quando tento duplicar por exemplo uma informação que é unica como a “descricao do bairro” uma exceção é lançada no metodo salvar da classe Conexao e remetido atravez do comando throw para o metodo salvar da classe Cadastro de Bairro. porém o erro que eu consigo captar é o seguinte :

javax.persistence.EntityExistsException: org.hibernate.exception.ConstraintViolationException: could not insert: [Beans.Bairro]

Porem atravez desta mensagem eu não consigo saber o que realmente aconteceu, por exemplo se foi uma duplicate key.Estou usando JPA/hibernate, pelo que pude perceber o hibernate capta o que eu estou querendo, mais não consegui mostrar esse erro extraindo-o do hibernate: Segue a mensagem do log de erro que o netbeans mostra:

13/08/2009 11:22:28 org.hibernate.util.JDBCExceptionReporter logExceptions //Eu quero esse codigo de erro WARNING: SQL Error: 1062, SQLState: 23000 13/08/2009 11:22:28 org.hibernate.util.JDBCExceptionReporter logExceptions //E quero essa mensagem SEVERE: Duplicate entry 'FLAUZINO' for key 2

B

Faz o seguinte manda o StackTrace da exeption quando houver
um erro de FK por exemplo pra eu dar uma olhada.
Abraço

J

Segue strackTrace:

14/08/2009 20:00:28 org.hibernate.util.JDBCExceptionReporter logExceptions WARNING: SQL Error: 1062, SQLState: 23000 14/08/2009 20:00:28 org.hibernate.util.JDBCExceptionReporter logExceptions SEVERE: Duplicate entry 'FLAUZINO' for key 2 javax.persistence.EntityExistsException: javax.persistence.EntityExistsException: org.hibernate.exception.ConstraintViolationException: could not insert: [Beans.Bairro] at Persistencia.Conexao.Salvar(Conexao.java:63) at Visao.Cadastros.FrmBairro.Salvar(FrmBairro.java:113) at HerancaVisual.MasterCadastro.jbSalvarActionPerformed(MasterCadastro.java:228) at HerancaVisual.MasterCadastro.access$000(MasterCadastro.java:20) at HerancaVisual.MasterCadastro$1.actionPerformed(MasterCadastro.java:51) at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995) at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318) at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387) at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236) at java.awt.Component.processMouseEvent(Component.java:6134) at javax.swing.JComponent.processMouseEvent(JComponent.java:3265) at java.awt.Component.processEvent(Component.java:5899) at java.awt.Container.processEvent(Container.java:2023) at java.awt.Component.dispatchEventImpl(Component.java:4501) at java.awt.Container.dispatchEventImpl(Container.java:2081) at java.awt.Component.dispatchEvent(Component.java:4331) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4301) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3965) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3895) at java.awt.Container.dispatchEventImpl(Container.java:2067) at java.awt.Window.dispatchEventImpl(Window.java:2458) at java.awt.Component.dispatchEvent(Component.java:4331) at java.awt.EventQueue.dispatchEvent(EventQueue.java:599) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122) Caused by: javax.persistence.EntityExistsException: org.hibernate.exception.ConstraintViolationException: could not insert: [Beans.Bairro] at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:612) at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:226) at Persistencia.Conexao.Salvar(Conexao.java:58) ... 29 more Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [Beans.Bairro] at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43) at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:40) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2158) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2638) at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:48) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250) at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298) at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107) at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49) at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:131) at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:87) at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:38) at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:618) at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:592) at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:596) at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:220) ... 30 more Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'FLAUZINO' for key 2 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.mysql.jdbc.Util.handleNewInstance(Util.java:406) at com.mysql.jdbc.Util.getInstance(Util.java:381) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1015) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1936) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2060) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2542) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1734) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2019) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1937) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1922) at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:73) at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:33) ... 45 more

B

Como eu imaginei as uma das causas, MySQLIntegrityConstraintViolationException, é uma SQLException.
Fiz um tratamento meio grosseiro pra você ter uma idéia de como chegar à exception correta.

Segue código de exemplo abaixo.
Abraço,

/**
	 * Efetua o tratamento de exceções do banco de dados.
	 * O método está exibindo uma mensagem Swing, porém
	 * isso é apenas uma idéia, o tratamento poderia se feito
	 * de várias formas
	 * 
	 * @param ex Uma instância de {@link Exception}
	 */
	public static void tratarDbException(Exception ex) {
		// Se a exceção base for um SQLException não
		// efetua a interação
		if (ex instanceof SQLException) {
			SQLException sqlEx = (SQLException) ex;
			JOptionPane.showMessageDialog(null,
					"Falha ao acessar banco de dados [CODIGO: "
							+ sqlEx.getErrorCode() + ", ERRO: "
							+ sqlEx.getMessage() + "]");

			return;
		}
		
		// Verifica nas causas das exceções se há 
		// um SQLException, limitando a no máximo 
		// 5 interações no Looping
		Throwable tmpEx = ex.getCause();
		int num = 0;
		while (tmpEx != null && num < 5) {
			num++;
			
			// Se a causa é um SQLException
			// exibe mensagem
			if (tmpEx instanceof SQLException) {
				SQLException sqlEx = (SQLException) ex;
				JOptionPane.showMessageDialog(null,
						"Falha ao acessar banco de dados [CODIGO: "
								+ sqlEx.getErrorCode() + ", ERRO: "
								+ sqlEx.getMessage() + "]");

				return;
			}
			
			// Se ainda não é um SQLException continua
			// a integração
			tmpEx = tmpEx.getCause();
		}
		
		// Se chegou até aqui, indica que dentro das causas
		// não foi encontrada um SQLException, e faz um tratamento 
		// genérico, a partir da Exception principal
		JOptionPane.showMessageDialog(null,
				"Falha inesperada ao acessar " +
				"banco de dados [ERRO: " + ex.getMessage() + "]");
	}
J

Deu Certo, muito obrigado! so tive que mudar a linha 33 para:

SQLException sqlEx = (SQLException) tmpEx;

Vou procurar implementar mais funcionalidades e posto o codigo aqui. Percebo que existem muitas pessoas com este problema e este post será de grande valia.

grato.

B

Estava olhando o código, se usar do {} wihle (), fica melhor…

Abraço,
Rodrigo

/**
	 * Efetua o tratamento de exceções do banco de dados.
	 * O método está exibindo uma mensagem Swing, porém
	 * isso é apenas uma idéia, o tratamento poderia se feito
	 * de várias formas
	 * 
	 * @param ex Uma instância de {@link Exception}
	 */
	public static void tratarDbException(Exception ex) {		
		// Verifica nas causas das exceções se há 
		// um SQLException, limitando a no máximo 
		// 5 interações no Looping
		Throwable tmpEx = ex;
		int num = 0;
		do {
			num++;
			
			// Se a causa é um SQLException
			// exibe mensagem
			if (tmpEx instanceof SQLException) {
				SQLException sqlEx = (SQLException) tmpEx;
				JOptionPane.showMessageDialog(null,
						"Falha ao acessar banco de dados [CODIGO: "
								+ sqlEx.getErrorCode() + ", ERRO: "
								+ sqlEx.getMessage() + "]");

				return;
			}
			
			// Se ainda não é um SQLException continua
			// a integração
			tmpEx = tmpEx.getCause();
		} while (tmpEx != null && num < 6);
		
		// Se chegou até aqui, indica que dentro das causas
		// não foi encontrada um SQLException, e faz um tratamento 
		// genérico, a partir da Exception principal
		JOptionPane.showMessageDialog(null,
				"Falha inesperada ao acessar " +
				"banco de dados [ERRO: " + ex.getMessage() + "]");
	}
Criado 14 de agosto de 2009
Ultima resposta 17 de ago. de 2009
Respostas 7
Participantes 2