当来自 db 的数据不好时是不是应该抛出异常?
Posted
技术标签:
【中文标题】当来自 db 的数据不好时是不是应该抛出异常?【英文标题】:Should an exception be thrown when the data from db is bad?当来自 db 的数据不好时是否应该抛出异常? 【发布时间】:2012-04-28 22:02:34 【问题描述】:在这个特定的应用程序中,没有单独的数据层,数据访问代码在实体本身中。例如,考虑一个客户实体,然后在定义成员和属性的 Customer.cs 文件中,您有如下方法来加载客户对象
public bool TryLoad(int customerID, out Customer customer)
bool success = false
try
//code which calls the db and fills a SqlDataReader
ReadDataFromSqlDataReader(reader);
success = true;
catch(Exception ex)
LogError();
success = false;
return success;
现在,在 ReadDataFromSqlDataReader(reader) 中,tryparse 用于将读取器中的数据加载到对象中。例如
public void ReadDataFromSqlDataReader(reader)
int.TryParse(reader["CustomerID"].ToString(), out this.CustomerID);
PhoneNumber.TryParse(reader["PhoneNumber"].ToString(), out this.PhoneNumber);
... similar TryParse code for all the other fields..
使用 TryParse 从读取器读取所有属性是一种好习惯吗?一位开发人员告诉我,这样做是因为 TryParse 比 int.Parse 具有更好的性能。但是,当您从数据库读取的值不符合您的代码期望的值时,您不希望抛出异常吗?我的意思是在这种情况下,如果数据库中的电话号码错误,那么可能根本不应该初始化该对象,而不是加载一个带有空电话号码的对象?
【问题讨论】:
对我来说听起来很特别TryParse
只有在处理不良数据时才具有更好的 Parse
性能。
我无法想象性能有什么不同。它吞下了异常,因此实际上包含了与您在外部使用 .Parse 编写的代码相同的代码。
只有当您尝试将数据库数据转换为不兼容的类型时,解析才会失败,对吧。虽然我猜有原生PhoneNumber
类型的数据库并不多
作为,TryParse
返回布尔值。所以,我可以在Boolean
值的基础上ByPass/Continue
Upcoming Logic/Any Database
请求。我不会让异常发生在这样的场景中。为此,我将进行日志记录等。
【参考方案1】:
作为,TryParse
返回布尔值。所以,我可以在Boolean
值的基础上ByPass/Continue
Upcoming Logic/Any Database
请求。我不会让异常发生在这样的场景中。为此,我将进行日志记录等。
解析
引发异常。 如果您确定该值有效,请使用它
TryParse
返回一个表示是否成功的布尔值 它只是在内部尝试/捕获为什么没有例外地实现,所以它很快 在值可能为 InValid 的情况下使用它
【讨论】:
【参考方案2】:我不会为此使用 TryParse。 如果我的数据库中有垃圾,我希望得到解决。 如果数据在解析方面不明确(例如,Varchar 带有 int 或 double 作为字符串) 我想整理一下我的架构,TryParse 作为类型检测将是一种快速而简单的技巧。
【讨论】:
【参考方案3】:将数据插入数据库时执行有效的验证。这不是一个好的设计,可以在数据库中输入错误的数据。如果数据库包含错误的电话号码,如果它是强制性的,则应要求用户再次输入电话号码,如果电话号码不是那么重要,您可以将电话号码初始化为 null 以防数据错误。
【讨论】:
【参考方案4】:是的,遵循 fail-fast 原则,您可能希望在返回无法转换为预期类型的值时抛出异常。
如果其中一项操作失败并且您继续执行,就好像什么都没发生一样,您可能会遇到难以捕捉且难以查明的奇怪错误:对象被添加到数据库中,而它们本应更新现有行,数据神秘消失,猫狗生活在一起……你懂的。
另一方面,如果您立即抛出异常,您就可以准确地知道问题出在哪里,并且可以在问题变得更糟之前发现并修复它。
TryParse
在失败的情况下会比Parse
工作得更快,这仅仅是因为它不必抛出异常(这可能很昂贵),但是如果你假设事情会成功(这段代码是不使用解析的结果),您应该使用Parse
获得相同的性能。
【讨论】:
作为,TryParse
返回布尔值。所以,我可以在Boolean
值的基础上ByPass/Continue
Upcoming Logic/Any Database
请求。我不会让异常发生在这样的场景中。为此,我将进行日志记录等。【参考方案5】:
如果你会处理它,那么是的,你应该抛出一个异常。但是,如果您不关心异常,并且如果您要过滤并使用正确的数据(在这种情况下为非零),您可以跳过。
【讨论】:
我完全不同意。调用此方法的程序员将假定他们获得的对象已完全填充。给他们一个未完全填充的对象是自找麻烦。即使没有处理代码,最好让系统发生严重故障并让您注意到您有错误这一事实,而不是让其余代码像没有任何问题一样使用这些数据。 你是对的,但这是一个选择。抛出或不抛出异常取决于你想要做什么。我说如果你关心你应该抛出一个异常,但可能并非总是如此。也许他想在用户界面的电话号码栏中显示一条消息,例如“您的电话号码无效。”。 如果我这样做并且它无效是一个例外。我会把它扔到调用者中,然后在调用代码中处理它。 (或 mabe 陷阱并引发自定义异常。将消息放入执行解析的代码中,意味着它在做不止一件事,意味着您必须做同样的事情或破坏 DRY,这将导致糟糕的设计,并使任何围绕 UI 相关的单元测试。所以一个选项是的,一个不错的选项,我很怀疑。 捕获每个异常(比如 1000 个项目)并进行处理可能是多余的,而不是为对象的字段分配一个简单的字符串。所以没有一般意义上的最好,只有性能、设计、可测试性等方面最好。 这都是相对的,但是如果 1000 条记录是一个显着的百分比,那么我会修复数据并根据性能提升证明这样做是合理的。如果你不得不忍受它,你必须确保它几乎是你唯一的选择,糟糕的设计可能会成为一个坏习惯。【参考方案6】:在插入和/或更新数据时,您正在执行哪种验证?
只要您在这里应用某种形式的验证,我个人就不会验证来自数据库的数据,因为您应该确信您只输入了有效数据。
【讨论】:
你能 100% 保证它总是好的数据吗?当 dba 直接打开表并输入“stjkerij”作为电话号码时会发生什么? 问题是系统最初开发时没有验证。例如,PhoneNumber 不是代码中定义的类型,它基本上是一个字符串。几年后,其中一位开发人员将 PhoneNumber 定义为一种类型,现在大多数情况下,每当插入数据时,它都是有效数据。但是旧代码的混乱,我不能 100% 确定来自数据库的数据总是有效的。此外,如果我失败并记录这些,我实际上可能能够从数据库中清除不良数据。 @JonH,数据好不好不重要,重要的是你能不能把它做得好,如果不是。以上是关于当来自 db 的数据不好时是不是应该抛出异常?的主要内容,如果未能解决你的问题,请参考以下文章
当查询具有 GROUP BY 子句时,Hive 查询抛出“来自 org.apache.hadoop.hive.ql.exec.tez.TezTask 的代码 2”异常
测试期间的Spring Boot JPA事务 - 不会在插入时抛出密钥违例异常