Guide de Spring NonTransientDataAccessException

Guide de l'exception nonTransientDataAccessException de printemps

1. Vue d'ensemble

Dans ce rapide tutoriel, nous allons passer en revue les types les plus importants desNonTransientDataAccessException communs et les illustrer avec des exemples.

Classe d'exception de base2. The

Les sous-classes de cette classe d'exceptions principale représentent des exceptions liées à l'accès aux données considérées comme non transitoires ou permanentes.

Autrement dit, cela signifie que, jusqu'à ce que la cause fondamentale soit résolue, toutes les tentatives futures d'une méthode ayant provoqué une exception échoueront.

3. DataIntegrityViolationException

Ce sous-type deNonTransientDataAccessException est renvoyé lorsqu'une tentative de modification des données provoque une violation d'une contrainte d'intégrité.

Dans notre exemple de la classeFoo, la colonne name est définie comme ne permettant pas la valeurnull:

@Column(nullable = false)
private String name;

Si nous essayons de sauvegarder une instance sans définir de valeur pour le nom, nous pouvons nous attendre à ce qu'unDataIntegrityViolationException soit lancé:

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

3.1. DuplicateKeyException

L'une des sous-classes desDataIntegrityViolationException estDuplicateKeyException, qui est lancée lorsqu'il y a une tentative de sauvegarde d'un enregistrement avec une clé primaire qui existe déjà ou une valeur qui est déjà présente dans une colonne avec ununique contrainte, telle que la tentative d'insérer deux lignes dans la tablefoo avec les mêmesid de 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

Cette exception est levée lorsqu'un problème lors de la récupération de données apparaît, tel que la recherche d'un objet avec un identifiant qui n'existe pas dans une base de données.

Par exemple, nous allons utiliser la classeJdbcTemplate qui a une méthode qui lève cette exception:

@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

Cette sous-classe d'exception est levée lors de la tentative de récupération de plusieurs colonnes d'une table sans créer lesRowMapper appropriés:

@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

Cette exception est levée lorsqu'un nombre d'enregistrements récupérés diffère de celui attendu, par exemple lorsque vous attendez une seule valeurInteger, mais que vous récupérez deux lignes pour la requête:

@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

Cette exception est levée lorsqu'il est impossible d'obtenir une source de données spécifiée. Pour l'exemple, nous utiliserons la classeJndiDataSourceLookup, pour rechercher une source de données inexistante:

@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

Cette exception est levée lorsqu'un accès à une ressource est incorrect, par exemple lorsqu'un utilisateur ne dispose pas des droitsSELECT.

Pour tester cette exception, nous devons révoquer le droitSELECT pour l'utilisateur, puis exécuter une requête 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");
    }
}

Notez que nous rétablissons la permission de l'utilisateur dans le blocfinally.

6.1 BadSqlGrammarException

Un sous-type très courant deInvalidDataAccessResourceUsageException estBadSqlGrammarException, qui est renvoyé lors d'une tentative d'exécution d'une requête avec un SQL non valide:

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

Remarquez bien sûr lefro – qui est l'aspect invalide de la requête.

7. CannotGetJdbcConnectionException

Cette exception est levée lorsqu'une tentative de connexion viaJDBC échoue, par exemple lorsque l'URL de la base de données est incorrecte. Si nous écrivons l'URL comme ceci:

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

Ensuite, lesCannotGetJdbcConnectionException seront lancés lors de la tentative d'exécution d'une instruction:

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

8. Conclusion

Dans ce didacticiel très précis, nous avons examiné certains des sous-types les plus courants de la classeNonTransientDataAccessException.

L'implémentation de tous les exemples peut être trouvée dansthe GitHub project. Et bien sûr, tous les exemples utilisent une base de données en mémoire afin que vous puissiez les exécuter facilement sans rien configurer.