Guia para Spring NonTransientDataAccessException
*1. Visão geral *
Neste tutorial rápido, examinaremos os tipos mais importantes do NonTransientDataAccessException comum e os ilustraremos com exemplos.
===* 2. A *Classe de exceção básica
As subclasses dessa classe de exceção principal representam exceções relacionadas ao acesso a dados, consideradas não transitórias ou permanentes.
Simplificando, isso significa que - até que a causa raiz seja corrigida - todas as tentativas futuras de um método que causou uma exceção falharão.
===* 3. DataIntegrityViolationException *
Esse subtipo de NonTransientDataAccessException é lançado quando uma tentativa de modificar dados causa uma violação de uma restrição de integridade.
No nosso exemplo da classe Foo, a coluna name é definida como não permitindo o valor null:
@Column(nullable = false)
private String name;
Se tentarmos salvar uma instância sem definir um valor para o nome, podemos esperar que um DataIntegrityViolationException seja lançado:
@Test(expected = DataIntegrityViolationException.class)
public void whenSavingNullValue_thenDataIntegrityException() {
Foo fooEntity = new Foo();
fooService.create(fooEntity);
}
====* 3.1 DuplicateKeyException *
Uma das subclasses de DataIntegrityViolationException é DuplicateKeyException, lançada quando há uma tentativa de salvar um registro com uma chave primária que já existe ou um valor que já está presente em uma coluna com uma restrição unique, como tentar inserir duas linhas na tabela foo com o mesmo id de 1:
@Test(expected = DuplicateKeyException.class)
public void whenSavingDuplicateKeyValues_thenDuplicateKeyException() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
jdbcTemplate.execute("insert into foo(id,name) values (1,'a')");
jdbcTemplate.execute("insert into foo(id,name) values (1,'b')");
}
===* 4. DataRetrievalFailureException *
Essa exceção é lançada quando um problema durante a recuperação de dados é exibido, como procurar um objeto com um identificador que não existe em um banco de dados.
Por exemplo, vamos usar a classe JdbcTemplate, que possui um método que lança essa exceção:
@Test(expected = DataRetrievalFailureException.class)
public void whenRetrievingNonExistentValue_thenDataRetrievalException() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
jdbcTemplate.queryForObject("select* from foo where id = 3", Integer.class);
}
4.1 IncorrectResultSetColumnCountException
Essa subclasse de exceção é lançada ao tentar recuperar várias colunas de uma tabela sem criar o RowMapper apropriado:
@Test(expected = IncorrectResultSetColumnCountException.class)
public void whenRetrievingMultipleColumns_thenIncorrectResultSetColumnCountException() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
jdbcTemplate.execute("insert into foo(id,name) values (1,'a')");
jdbcTemplate.queryForList("select id,name from foo where id=1", Foo.class);
}
4.2 IncorrectResultSizeDataAccessException
Essa exceção é lançada quando vários registros recuperados diferem do esperado, por exemplo, ao esperar um único valor Integer, mas ao recuperar duas linhas para a consulta:
@Test(expected = IncorrectResultSizeDataAccessException.class)
public void whenRetrievingMultipleValues_thenIncorrectResultSizeException() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
jdbcTemplate.execute("insert into foo(name) values ('a')");
jdbcTemplate.execute("insert into foo(name) values ('a')");
jdbcTemplate.queryForObject("select id from foo where name='a'", Integer.class);
}
*5. DataSourceLookupFailureException *
Essa exceção é lançada quando uma fonte de dados especificada não pode ser obtida. Por exemplo, usaremos a classe JndiDataSourceLookup, para procurar uma fonte de dados inexistente:
@Test(expected = DataSourceLookupFailureException.class)
public void whenLookupNonExistentDataSource_thenDataSourceLookupFailureException() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
dsLookup.setResourceRef(true);
DataSource dataSource = dsLookup.getDataSource("java:comp/env/jdbc/example_db");
}
===* 6. InvalidDataAccessResourceUsageException *
Essa exceção é lançada quando um recurso é acessado incorretamente, por exemplo, quando um usuário não possui direitos SELECT.
Para testar essa exceção, precisamos revogar o SELECT certo para o usuário e, em seguida, execute uma consulta SELECT:
@Test(expected = InvalidDataAccessResourceUsageException.class)
public void whenRetrievingDataUserNoSelectRights_thenInvalidResourceUsageException() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
jdbcTemplate.execute("revoke select from tutorialuser");
try {
fooService.findAll();
} finally {
jdbcTemplate.execute("grant select to tutorialuser");
}
}
Observe que estamos restaurando a permissão do usuário no bloco finally.
====* 6.1 BadSqlGrammarException *
Um subtipo muito comum de InvalidDataAccessResourceUsageException é BadSqlGrammarException, que é lançado ao tentar executar uma consulta com SQL inválido:
@Test(expected = BadSqlGrammarException.class)
public void whenIncorrectSql_thenBadSqlGrammarException() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
jdbcTemplate.queryForObject("select* fro foo where id=3", Integer.class);
}
Observe, é claro, o fro –, que é o aspecto inválido da consulta.
*7. CannotGetJdbcConnectionException *
Essa exceção é lançada quando uma tentativa de conexão através de JDBC falha, por exemplo, quando o URL do banco de dados está incorreto. Se escrevermos o URL da seguinte forma:
jdbc.url=jdbc:mysql:3306://localhost/spring_hibernate4_exceptions?createDatabaseIfNotExist=true
Em seguida, o CannotGetJdbcConnectionException será lançado ao tentar executar uma instrução:
@Test(expected = CannotGetJdbcConnectionException.class)
public void whenJdbcUrlIncorrect_thenCannotGetJdbcConnectionException() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
jdbcTemplate.execute("select* from foo");
}
8. Conclusão
Neste tutorial direto ao ponto, vimos alguns dos subtipos mais comuns da classe NonTransientDataAccessException.
A implementação de todos os exemplos pode ser encontrada em o projeto GitHub. E é claro que todos os exemplos estão usando um banco de dados na memória para que você possa executá-los facilmente sem configurar nada.