返回介绍

10.1.1 了解 Spring 的数据访问异常体系

发布于 2024-08-17 00:45:49 字数 3654 浏览 0 评论 0 收藏 0

这里有一个关于跳伞运动员的经典笑话,这个运动员被风吹离正常路线后降落在树上并高高地挂在那里。后来,有人路过,跳伞运动员就问他自己在什么地方。过路人回答说:“你在离地大约20尺的空中。”跳伞运动员说:“你一定是个软件分析师。”过路人回应说“你说对了。你是怎么知道的呢?”“因为你跟我说的话百分百正确,但丝毫用处都没有。”

这个故事已经听过很多遍了,每次过路人的职业或国籍都会有所不同。但是这个故事使我想起了JDBC中的SQLException。如果你曾经编写过JDBC代码(不使用Spring),你肯定会意识到如果不强制捕获SQLException的话,几乎无法使用JDBC做任何事情。SQLException表示在尝试访问数据库的时出现了问题,但是这个异常却没有告诉你哪里出错了以及如何进行处理。

可能导致抛出SQLException的常见问题包括:

应用程序无法连接数据库;

要执行的查询存在语法错误;

查询中所使用的表和/或列不存在;

试图插入或更新的数据违反了数据库约束。

SQLException的问题在于捕获到它的时候该如何处理。事实上,能够触发SQLException的问题通常是不能在catch代码块中解决的。大多数抛出SQLException的情况表明发生了致命性错误。如果应用程序不能连接到数据库,这通常意味着应用不能继续使用了。类似地,如果查询时出现了错误,那在运行时基本上也是无能为力。

如果无法从SQLException中恢复,那为什么我们还要强制捕获它呢?

即使对某些SQLException有处理方案,我们还是要捕获SQLException并查看其属性才能获知问题根源的更多信息。这是因为SQLException被视为处理数据访问所有问题的通用异常。对于所有的数据访问问题都会抛出SQLException,而不是对每种可能的问题都会有不同的异常类型。

一些持久化框架提供了相对丰富的异常体系。例如,Hibernate提供了二十个左右的异常,分别对应于特定的数据访问问题。这样就可以针对想处理的异常编写catch代码块。

即便如此,Hibernate的异常是其本身所特有的。正如前面所言,我们想将特定的持久化机制独立于数据访问层。如果抛出了Hibernate所特有的异常,那我们对Hibernate的使用将会渗透到应用程序的其他部分。如果不这样做的话,我们就得捕获持久化平台的异常,然后将其作为平台无关的异常再次抛出。

一方面,JDBC的异常体系过于简单了——实际上,它算不上一个体系。另一方面,Hibernate的异常体系是其本身所独有的。我们需要的数据访问异常要具有描述性而且又与特定的持久化框架无关。

Spring所提供的平台无关的持久化异常

Spring JDBC提供的数据访问异常体系解决了以上的两个问题。不同于JDBC,Spring提供了多个数据访问异常,分别描述了它们抛出时所对应的问题。表10.1对比了Spring的部分数据访问异常以及JDBC所提供的异常。

从表中可以看出,Spring为读取和写入数据库的几乎所有错误都提供了异常。Spring的数据访问异常要比表10.1所列的还要多。(在此没有列出所有的异常,因为我不想让JDBC显得太寒酸。)

表10.1 JDBC的异常体系与Spring的数据访问异常

JDBC的异常

Spring的数据访问异常

BatchUpdateException
DataTruncation
SQLException
SQLWarning

BadSqlGrammarException
CannotAcquireLockException
CannotSerializeTransactionException
CannotGetJdbcConnectionException
CleanupFailureDataAccessException
ConcurrencyFailureException
DataAccessException
DataAccessResourceFailureException
DataIntegrityViolationException
DataRetrievalFailureException
DataSourceLookupApiUsageException
DeadlockLoserDataAccessException
DuplicateKeyException
EmptyResultDataAccessException
IncorrectResultSizeDataAccessException
IncorrectUpdateSemanticsDataAccessException
InvalidDataAccessApiUsageException
InvalidDataAccessResourceUsageException
InvalidResultSetAccessException
JdbcUpdateAffectedIncorrectNumberOfRowsException
LbRetrievalFailureException

BatchUpdateException
DataTruncation
SQLException
SQLWarning

NonTransientDataAccessResourceException
OptimisticLockingFailureException
PermissionDeniedDataAccessException
PessimisticLockingFailureException
QueryTimeoutException
RecoverableDataAccessException
SQLWarningException
SqlXmlFeatureNotImplementedException
TransientDataAccessException
TransientDataAccessResourceException
TypeMismatchDataAccessException
UncategorizedDataAccessException
UncategorizedSQLException

尽管Spring的异常体系比JDBC简单的SQLException丰富得多,但它并没有与特定的持久化方式相关联。这意味着我们可以使用Spring抛出一致的异常,而不用关心所选择的持久化方案。这有助于我们将所选择持久化机制与数据访问层隔离开来。

看!不用写catch代码块

表10.1中没有体现出来的一点就是这些异常都继承自DataAccessException。DataAccessException的特殊之处在于它是一个非检查型异常。换句话说,没有必要捕获Spring所抛出的数据访问异常(当然,如果你想捕获的话也是完全可以的)。

DataAccessException只是Sping处理检查型异常和非检查型异常哲学的一个范例。Spring认为触发异常的很多问题是不能在catch代码块中修复的。Spring使用了非检查型异常,而不是强制开发人员编写catch代码块(里面经常是空的)。这把是否要捕获异常的权力留给了开发人员。

为了利用Spring的数据访问异常,我们必须使用Spring所支持的数据访问模板。让我们看一下Spring的模板是如何简化数据访问的。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文