«1. Обзор

В этом кратком руководстве мы рассмотрим наиболее важные типы распространенных исключений NonTransientDataAccessException и проиллюстрируем их примерами.

2. Базовый класс исключений

Подклассы этого основного класса исключений представляют исключения, связанные с доступом к данным, которые считаются невременными или постоянными.

Проще говоря, это означает, что до тех пор, пока основная причина не будет устранена, все будущие попытки метода, вызвавшего исключение, будут неудачными.

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, которое выбрасывается при попытке сохранить запись с уже существующим первичным ключом или значением, которое уже присутствует в столбце с уникальным ограничением, например при попытке для вставки двух строк в таблицу 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 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);
}

7. CannotGetJdbcConnectionException

Это исключение выдается при неудачной попытке подключения через JDBC, например, при неверном URL-адресе базы данных. Если мы напишем URL следующим образом:

Тогда при попытке выполнить инструкцию будет выброшено исключение CannotGetJdbcConnectionException:

jdbc.url=jdbc:mysql:3306://localhost/spring_hibernate4_exceptions?createDatabaseIfNotExist=true

8. Заключение

@Test(expected = CannotGetJdbcConnectionException.class)
public void whenJdbcUrlIncorrect_thenCannotGetJdbcConnectionException() {
    JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
    jdbcTemplate.execute("select * from foo");
}

В этом очень точном уроке мы посмотрите на некоторые из наиболее распространенных подтипов класса NonTransientDataAccessException.

Реализацию всех примеров можно найти в проекте GitHub. И, конечно же, все примеры используют базу данных в памяти, так что вы можете легко запускать их, ничего не настраивая.

«