1. Обзор
В этом кратком руководстве мы рассмотрим наиболее важные типы распространенных исключений NonTransientDataAccessException
и проиллюстрируем их примерами.
2. Базовый класс исключений
Подклассы этого основного класса исключений представляют исключения, связанные с доступом к данным, которые считаются невременными или постоянными.
Проще говоря, это означает, что до тех пор, пока основная причина не будет устранена, все будущие попытки метода, вызвавшего исключение, будут неудачными.
3. Исключение DataIntegrityViolationException
Этот подтип NonTransientDataAccessException
вызывается, когда попытка изменить данные приводит к нарушению ограничения целостности.
В нашем примере класса Foo
столбец имени определен как не допускающий нулевого
значения:
@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
, который выдается при попытке сохранить запись с уже существующим первичным ключом или значением, которое уже присутствует в столбце с уникальным
ограничением, например при попытке вставить две строки . в таблице foo с тем же
идентификатором
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. Инкоректресултсетколумнкаунтексцептион
Этот подкласс исключения возникает при попытке получить несколько столбцов из таблицы без создания надлежащего 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. Инкорректрезультатсизедатаакцессцептион
Это исключение выдается, когда количество полученных записей отличается от ожидаемого, например, при ожидании одного целочисленного
значения, но получении двух строк для запроса:
@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
.
Реализацию всех примеров можно найти в проекте GitHub . И, конечно же, все примеры используют базу данных в памяти, так что вы можете легко запускать их, ничего не настраивая.