1. 概述
本快速教程將介紹最常見的 <em >NonTransientDataAccessException</em> 的主要類型,並提供示例説明。
2. 基異常類
該異常類是子類,代表與數據訪問相關的異常,這些異常被認為是不可變(非瞬態)或永久性的。
簡單來説,這意味着——在根原因未修復之前,導致異常的方法的所有後續嘗試都將失敗。
3. 數據完整性違反異常 (DataIntegrityViolationException)
本異常類型是 非瞬態數據訪問異常 (NonTransientDataAccessException) 的一個子類型,當嘗試修改數據時,如果違反了完整性約束時拋出。
在我們的 Foo 類示例中,name 列被定義為不允許 null 值的狀態:
@Column(nullable = false)
private String name;如果嘗試在未為名稱設置值的情況下保存一個實例,我們預計將會拋出 <em DataIntegrityViolationException 異常:
@Test(expected = DataIntegrityViolationException.class)
public void whenSavingNullValue_thenDataIntegrityException() {
Foo fooEntity = new Foo();
fooService.create(fooEntity);
}3.1. DuplicateKeyException
DuplicateKeyException 是 DataIntegrityViolationException 的一個子類,當嘗試保存一個具有已存在的主鍵或在具有 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. 數據源查找失敗異常
當指定的數據庫連接池無法獲取時,會拋出此異常。例如,我們將使用 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_hibernate5_exceptions?createDatabaseIfNotExist=true然後,當嘗試執行語句時,將會拋出 <emCanNotGetJdbcConnectionException 異常。
@Test(expected = CannotGetJdbcConnectionException.class)
public void whenJdbcUrlIncorrect_thenCannotGetJdbcConnectionException() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
jdbcTemplate.execute("select * from foo");
}8. 結論
在本教程中,我們深入探討了 NonTransientDataAccessException 類中最常見的幾種子類型。