Рубрики
Без рубрики

Руководство по Spring NonTransientDataAccessException

Руководство по наиболее распространенным типам исключения Spring NonTransientDataAccessException.

Автор оригинала: Loredana Crusoveanu.

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

Это исключение возникает, когда количество извлеченных записей отличается от ожидаемого, например, при ожидании одной Целое число значение, но получение двух строк для запроса:

@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 is 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 . И, конечно же, все примеры используют базу данных в памяти, так что вы можете легко запустить их, ничего не настраивая.