Leitfaden für Spring NonTransientDataAccessException

Leitfaden für Spring NonTransientDataAccessException

1. Überblick

In diesem kurzen Tutorial werden wir die wichtigsten Typen der allgemeinenNonTransientDataAccessExceptiondurchgehen und sie anhand von Beispielen veranschaulichen.

2. The Basisausnahmeklasse

Unterklassen dieser Hauptausnahmeklasse stellen datenzugriffsbezogene Ausnahmen dar, die als nicht vorübergehend oder dauerhaft betrachtet werden.

Einfach ausgedrückt bedeutet dies, dass - bis die Grundursache behoben ist - alle zukünftigen Versuche einer Methode, die eine Ausnahme verursacht hat, fehlschlagen.

3. DataIntegrityViolationException

Dieser Subtyp vonNonTransientDataAccessException wird ausgelöst, wenn ein Versuch, Daten zu ändern, eine Verletzung einer Integritätsbeschränkung verursacht.

In unserem Beispiel für die KlasseFoo ist die Namensspalte so definiert, dass der Wert vonnullnicht zulässig ist:

@Column(nullable = false)
private String name;

Wenn wir versuchen, eine Instanz zu speichern, ohne einen Wert für den Namen festzulegen, können wir erwarten, dassDataIntegrityViolationException ausgelöst werden:

@Test(expected = DataIntegrityViolationException.class)
public void whenSavingNullValue_thenDataIntegrityException() {
    Foo fooEntity = new Foo();
    fooService.create(fooEntity);
}

3.1. DuplicateKeyException

Eine der Unterklassen vonDataIntegrityViolationException istDuplicateKeyException, die ausgelöst wird, wenn versucht wird, einen Datensatz mit einem bereits vorhandenen Primärschlüssel oder einem Wert zu speichern, der bereits in einer Spalte mitunique Einschränkung, z. B. der Versuch, zwei Zeilen mit demselbenid von 1 in die Tabellefoo einzufügen:

@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

Diese Ausnahme wird ausgelöst, wenn beim Abrufen von Daten ein Problem auftritt, z. B. das Nachschlagen eines Objekts mit einer Kennung, die in einer Datenbank nicht vorhanden ist.

Zum Beispiel werden wir die KlasseJdbcTemplateverwenden, die eine Methode hat, die diese Ausnahme auslöst:

@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

Diese Ausnahmeunterklasse wird ausgelöst, wenn versucht wird, mehrere Spalten aus einer Tabelle abzurufen, ohne die richtigenRowMapper zu erstellen:

@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

Diese Ausnahme wird ausgelöst, wenn sich eine Anzahl der abgerufenen Datensätze von der erwarteten unterscheidet, z. B. wenn ein einzelnerInteger-Wert erwartet wird, aber zwei Zeilen für die Abfrage abgerufen werden:

@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

Diese Ausnahme wird ausgelöst, wenn eine angegebene Datenquelle nicht abgerufen werden kann. Für das Beispiel verwenden wir die KlasseJndiDataSourceLookup, um nach einer nicht vorhandenen Datenquelle zu suchen:

@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

Diese Ausnahme wird ausgelöst, wenn auf eine Ressource falsch zugegriffen wird, z. B. wenn einem Benutzer die Rechte vonSELECTfehlen.

Um diese Ausnahme zu testen, müssen wir dasSELECT-Recht für den Benutzer widerrufen und dann eine SELECT-Abfrage ausführen:

@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");
    }
}

Beachten Sie, dass wir die Berechtigung für den Benutzer im Blockfinallywiederherstellen.

6.1 BadSqlGrammarException

Ein sehr häufiger Subtyp vonInvalidDataAccessResourceUsageException istBadSqlGrammarException, der ausgelöst wird, wenn versucht wird, eine Abfrage mit ungültigem SQL auszuführen:

@Test(expected = BadSqlGrammarException.class)
public void whenIncorrectSql_thenBadSqlGrammarException() {
    JdbcTemplate jdbcTemplate = new JdbcTemplate(restDataSource);
    jdbcTemplate.queryForObject("select * fro foo where id=3", Integer.class);
}

Beachten Sie natürlich diefro –, die der ungültige Aspekt der Abfrage sind.

7. CannotGetJdbcConnectionException

Diese Ausnahme wird ausgelöst, wenn ein Verbindungsversuch überJDBC fehlschlägt, z. B. wenn die Datenbank-URL falsch ist. Wenn wir die URL wie folgt schreiben:

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

Dann wirdCannotGetJdbcConnectionException ausgelöst, wenn versucht wird, eine Anweisung auszuführen:

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

8. Fazit

In diesem sehr detaillierten Tutorial haben wir uns einige der häufigsten Untertypen der KlasseNonTransientDataAccessExceptionangesehen.

Die Implementierung aller Beispiele kann inthe GitHub project gefunden werden. Und natürlich verwenden alle Beispiele eine In-Memory-Datenbank, sodass Sie sie problemlos ausführen können, ohne etwas einzurichten.