Spring NonTransientDataAccessExceptionガイド

Spring NonTransientDataAccessExceptionのガイド

1. 概要

このクイックチュートリアルでは、一般的なNonTransientDataAccessExceptionの最も重要なタイプを確認し、例を挙げて説明します。

2. The基本例外クラス

このメインの例外クラスのサブクラスは、非一時的または永続的と見なされるデータアクセス関連の例外を表します。

簡単に言えば、つまり、根本的な原因が修正されるまで、例外を引き起こしたメソッドの今後の試行はすべて失敗するということです。

3. DataIntegrityViolationException

このNonTransientDataAccessExceptionのサブタイプは、データを変更しようとすると整合性制約に違反した場合にスローされます。

Fooクラスの例では、名前列は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のサブクラスの1つはDuplicateKeyExceptionです。これは、すでに存在する主キーまたは%((t1)の列にすでに存在する値でレコードを保存しようとしたときにスローされます1の同じidfooテーブルに2つの行を挿入しようとするなど、t2)s制約。

@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値を期待しているが、クエリに対して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クラスの最も一般的なサブタイプのいくつかを見てきました。

すべての例の実装はthe GitHub projectにあります。 そしてもちろん、すべての例はインメモリデータベースを使用しているため、何も設定せずに簡単に実行できます。