为什么存储库模式示例从不处理数据库连接异常?

Why do Examples of the Repository Pattern never deal with Database Connection Exceptions?

我阅读了很多教程并看到了很多关于 Repository 模式实现的代码示例。在几乎所有情况下,都没有解决在数据库不可用时尝试访问数据库而导致的异常。考虑到如果数据库位于网络上的某个位置,这是一个非常现实的场景,这似乎很奇怪。

那么处理这些异常的最佳做法是什么?

首先,因为SRP。一个class只负责一个且只有一个职责。至少在某种程度上是这样。

其次,这取决于您需要如何处理失败。您会 向用户显示错误消息 吗? 在应用层处理,因为数据层和业务层不知道UI那里有什么。

如果你有逻辑,例如:如果数据库不能访问,使用离线缓存,使用Decorator pattern或类似的方式处理,例如:

public class OnlineUserRepository : IUserRepository{
    public User Get(){ /* get the user from online source */ }
}

public class OfflineUserRepository : IUserRepository{
    public User Get(){ /* get the user from offline source */ }
}

public class UserRepository : IUserRepository{
    public UserRepository(IUserRepository onlineRepo, IUserRepository offlineRepo){
        //parameter assignment
    }
    IUserRepository onlineRepo;
    IUserRepository offlineRepo;
    public User Get(){
        try{
            onlineRepo.Get();
        }
        catch{
            return offlineRepo.Get();
        }
    }
}

为什么要这样处理?同样,因为 SRP.

老实说,我认为这个问题没有得到解决,因为关于如何处理异常的争论一直在进行(而且情绪激动)。关于异常应该在本地处理(在那里有更大的机会理解它们并做一些聪明的事情,比如重试)还是在 UI 层处理(其中 99.9% 的异常最终冒泡),人们一直在争论不休最多)。

就个人而言,我发现在 Repository 层内执行 try/catch 最优雅,以捕获特定于数据库的异常,并抛出我自己创建的新异常。这给了我一个放置重试逻辑的地方。然后我还可以决定 DAOException 是已检查异常还是运行时异常。

这允许用户界面处理已知的异常,并帮助我将更高级别的层与任何特定于提供程序的错误隔离开来。例如,如果我将我的数据存储迁移到 No-SQL 数据库,如 Mongo 或 Cassandra,我仍然可以抛出相同的异常,并保持它们的语义,而无需更改所有调用代码。