Руководство по Spring NonTransientDataAccessException
1. обзор
В этом кратком руководстве мы рассмотрим наиболее важные типы общихNonTransientDataAccessException и проиллюстрируем их примерами.
2. The Базовый класс исключения
Подклассы этого основного класса исключений представляют исключения, связанные с доступом к данным, которые считаются непереходными или постоянными.
Проще говоря, это означает, что - пока не будет устранена основная причина - все будущие попытки метода, вызвавшего исключение, будут безуспешными.
3. DataIntegrityViolationExceptionс
Этот подтипNonTransientDataAccessException выдается, когда попытка изменить данные вызывает нарушение ограничения целостности.
В нашем примере классаFoo столбец name определен как не допускающий значениеnull:
@Column(nullable = false)
private String name;
Если мы попытаемся сохранить экземпляр без установки значения для имени, мы можем ожидать выбросаDataIntegrityViolationException:
@Test(expected = DataIntegrityViolationException.class)
public void whenSavingNullValue_thenDataIntegrityException() {
Foo fooEntity = new Foo();
fooService.create(fooEntity);
}
3.1. DuplicateKeyExceptionс
Одним из подклассовDataIntegrityViolationException являетсяDuplicateKeyException, который выдается, когда есть попытка сохранить запись с уже существующим первичным ключом или значением, которое уже присутствует в столбце сunique, например, попытка вставить две строки в таблицуfoo с тем жеid равным 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с
Это исключение возникает, когда возникает проблема во время извлечения данных, например, поиск объекта с идентификатором, которого нет в базе данных.
Например, мы собираемся использовать классJdbcTemplate, у которого есть метод, который генерирует это исключение:
@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
Этот подкласс исключения генерируется при попытке получить несколько столбцов из таблицы без создания правильного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
Это исключение возникает, когда количество извлеченных записей отличается от ожидаемого, например, когда ожидается одно значениеInteger, но извлекаются две строки для запроса:
@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с
Это исключение выдается, когда указанный источник данных не может быть получен. В этом примере мы будем использовать классJndiDataSourceLookup, чтобы искать несуществующий источник данных:
@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с
Это исключение возникает при неправильном доступе к ресурсу, например, когда пользователю не хватает правSELECT.
Чтобы протестировать это исключение, нам нужно отозвать правоSELECT для пользователя, а затем выполнить запрос 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");
}
}
Обратите внимание, что мы восстанавливаем разрешение для пользователя в блокеfinally.
6.1 BadSqlGrammarException
Очень распространенным подтипомInvalidDataAccessResourceUsageException являетсяBadSqlGrammarException, который выдается при попытке выполнить запрос с недопустимым SQL:
@Test(expected = BadSqlGrammarException.class)
public void whenIncorrectSql_thenBadSqlGrammarException() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
jdbcTemplate.queryForObject("select * fro foo where id=3", Integer.class);
}
Обратите внимание, конечно, наfro –, который является недопустимым аспектом запроса.
7. CannotGetJdbcConnectionExceptionс
Это исключение возникает, когда попытка подключения черезJDBC не удалась, например, если URL-адрес базы данных неверен. Если мы напишем URL, как показано ниже:
jdbc.url=jdbc:mysql:3306://localhost/spring_hibernate4_exceptions?createDatabaseIfNotExist=true
ТогдаCannotGetJdbcConnectionException будет брошен при попытке выполнить оператор:
@Test(expected = CannotGetJdbcConnectionException.class)
public void whenJdbcUrlIncorrect_thenCannotGetJdbcConnectionException() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
jdbcTemplate.execute("select * from foo");
}
8. Заключение
В этом очень подробном руководстве мы рассмотрели некоторые из наиболее распространенных подтипов классаNonTransientDataAccessException.
Реализации всех примеров можно найти вthe GitHub project. И, конечно, все примеры используют базу данных в памяти, так что вы можете легко запустить их, ничего не настраивая.