The Master Class of "Learn Spring Security" is out:
1. Overview
In this quick tutorial, we will go through the most important types of the common NonTransientDataAccessException and illustrate them with examples.
2. The Base Exception Class
Subclasses of this main exception class represent data access related exceptions which are considered non-transient or permanent.
Simply put, that means that – until the root cause is fixed – all future attempts of a method that caused an exception, will fail.
3. DataIntegrityViolationException
This subtype of NonTransientDataAccessException is thrown when an attempt to modify data causes a violation of an integrity constraint.
In our example of the Foo class, the name column is defined as not allowing the null value:
@Column(nullable = false) private String name;
If we attempt to save an instance without setting a value for the name, we can expect a DataIntegrityViolationException to be thrown:
@Test(expected = DataIntegrityViolationException.class) public void whenSavingNullValue_thenDataIntegrityException() { Foo fooEntity = new Foo(); fooService.create(fooEntity); }
3.1. DuplicateKeyException
One of subclasses of the DataIntegrityViolationException is DuplicateKeyException, which is thrown when there is an attempt to save a record with a primary key that already exists or a value that is already present in a column with a unique constraint, such as attempting to insert two rows in the foo table with the same id of 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
This exception is thrown when a problem during retrieving data appears, such as looking up an object with an identifier which doesn’t exist in a database.
For example, we’re going to use the JdbcTemplate class which has a method that throws this exception:
@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
This exception subclass is thrown when attempting to retrieve multiple columns from a table without creating the proper RowMapper:
@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
This exception is thrown when a number of retrieved records differs from expected one, for example when expecting a single Integer value, but retrieving two rows for the query:
@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
This exception is thrown when a specified data source cannot be obtained. For the example, we will use the class JndiDataSourceLookup, to look for a nonexistent data source:
@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
This exception is thrown when a resource is accessed incorrectly, for example when a user lacks SELECT rights.
In order to test this exception, we’ll need to revoke the SELECT right for the user, then run a SELECT query:
@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"); } }
Notice that we are restoring the permission on the user in the finally block.
6.1 BadSqlGrammarException
A very common subtype of InvalidDataAccessResourceUsageException is BadSqlGrammarException, which is thrown when attempting to run a query with invalid SQL:
@Test(expected = BadSqlGrammarException.class) public void whenIncorrectSql_thenBadSqlGrammarException() { JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource); jdbcTemplate.queryForObject("select * fro foo where id=3", Integer.class); }
Notice of course the fro – which is the invalid aspect of the query.
7. CannotGetJdbcConnectionException
This exception is thrown when a connection attempt through JDBC fails, for example when the database url is incorrect. If we write the url like the following:
jdbc.url=jdbc:mysql:3306://localhost/spring_hibernate4_exceptions?createDatabaseIfNotExist=true
Then the CannotGetJdbcConnectionException will be thrown when attempting to execute a statement:
@Test(expected = CannotGetJdbcConnectionException.class) public void whenJdbcUrlIncorrect_thenCannotGetJdbcConnectionException() { JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource); jdbcTemplate.execute("select * from foo"); }
8. Conclusion
In this very to the point tutorial we had a look at some of the most common subtypes of the NonTransientDataAccessException class.
The implementation of all examples can be found in the GitHub project. And of course all examples are using an in-memory database so you can easily run them without setting anything up.