Guide to Spring NonTransientDataAccessException – Spring NonTransientDataAccessException指南

最后修改: 2016年 8月 11日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick tutorial, we will go through the most important types of the common NonTransientDataAccessException and illustrate them with examples.

在这个快速教程中,我们将了解常见的NonTransientDataAccessException的最重要类型,并通过实例进行说明。

2. The Base Exception Class

2.基础异常类

Subclasses of this main exception class represent data access related exceptions which are considered non-transient or permanent.

这个主异常类的子类代表了与数据访问相关的异常,这些异常被认为是非暂时性的或永久性的。

Simply put, that means that – until the root cause is fixed – all future attempts of a method that caused an exception, will fail.

简单地说,这意味着–在根本原因得到解决之前–所有未来对引起异常的方法的尝试都会失败。

3. DataIntegrityViolationException

3、DataIntegrityViolationException

This subtype of NonTransientDataAccessException is thrown when an attempt to modify data causes a violation of an integrity constraint.

当试图修改数据导致违反完整性约束时,会抛出NonTransientDataAccessException的这个子类型。

In our example of the Foo class, the name column is defined as not allowing the null value:

在我们的Foo类的例子中,name列被定义为不允许出现null值。

@Column(nullable = false)
private String name;

If we attempt to save an instance without setting a value for the name, we can expect a DataIntegrityViolationException to be thrown:

如果我们试图保存一个实例而不为名字设置一个值,我们可以期待一个DataIntegrityViolationException的抛出。

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

3.1. DuplicateKeyException

3.1.DuplicateKeyException

One of subclasses of the DataIntegrityViolationException is DuplicateKeyException, which is thrown when there is an attempt to save a record with a primary key that already exists or a value that is already present in a column with a unique constraint, such as attempting to insert two rows in the foo table with the same id of 1:

DataIntegrityViolationException的一个子类是DuplicateKeyException,当试图保存一个主键已经存在的记录,或者一个值已经存在于具有unique约束的列中,例如试图在foo表中插入两条具有相同id的记录,就会抛出这个问题。

@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

4、DataRetrievalFailureException

This exception is thrown when a problem during retrieving data appears, such as looking up an object with an identifier which doesn’t exist in a database.

当在检索数据的过程中出现问题时,例如用数据库中不存在的标识符查找一个对象时,就会抛出这个异常。

For example, we’re going to use the JdbcTemplate class which has a method that throws this exception:

例如,我们要使用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

4.1.IncorrectResultSetColumnCountException

This exception subclass is thrown when attempting to retrieve multiple columns from a table without creating the proper RowMapper:

当试图从一个表中检索多列而不创建适当的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

4.2.IncorrectResultSizeDataAccessException

This exception is thrown when a number of retrieved records differs from expected one, for example when expecting a single Integer value, but retrieving two rows for the query:

当检索到的记录数量与预期的不同时,就会抛出这个异常,例如,当预期是一个单一的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. DataSourceLookupFailureException

5.DataSourceLookupFailureException

This exception is thrown when a specified data source cannot be obtained. For the example, we will use the class JndiDataSourceLookup, to look for a nonexistent data source:

当指定的数据源不能被获取时,就会抛出这个异常。在这个例子中,我们将使用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

6.InvalidDataAccessResourceUsageException

This exception is thrown when a resource is accessed incorrectly, for example when a user lacks SELECT rights.

当一个资源被错误地访问时,例如当一个用户缺乏SELECT权限时,就会抛出这个异常。

In order to test this exception, we’ll need to revoke the SELECT right for the user, then run a SELECT query:

为了测试这个异常,我们需要撤销用户的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");
    }
}

Notice that we are restoring the permission on the user in the finally block.

注意,我们在finally块中恢复了用户的权限。

6.1. BadSqlGrammarException

6.1.BadSqlGrammarException

A very common subtype of InvalidDataAccessResourceUsageException is BadSqlGrammarException, which is thrown when attempting to run a query with invalid SQL:

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

Notice of course the fro – which is the invalid aspect of the query.

当然,请注意fro – ,这是查询中无效的方面。

7. CannotGetJdbcConnectionException

7、CannotGetJdbcConnectionException

This exception is thrown when a connection attempt through JDBC fails, for example when the database url is incorrect. If we write the url like the following:

当通过JDBC的连接尝试失败时,例如当数据库网址不正确时,就会抛出这个异常。如果我们把网址写成下面这样。

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

Then the CannotGetJdbcConnectionException will be thrown when attempting to execute a statement:

那么在试图执行一个语句时,将抛出CannotGetJdbcConnectionException

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

8. Conclusion

8.结论

In this very to the point tutorial we had a look at some of the most common subtypes of the NonTransientDataAccessException class.

在这个非常有意义的教程中,我们看了NonTransientDataAccessException类的一些最常见的子类型。

The implementation of all examples can be found in the GitHub project. And of course all examples are using an in-memory database so you can easily run them without setting anything up.

所有例子的实现都可以在GitHub项目中找到。当然,所有的例子都是使用内存数据库,所以你可以轻松地运行它们,而无需设置任何东西。