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