在 Web 应用程序中选择静态和实例数据访问类的优缺点是啥?

Posted

技术标签:

【中文标题】在 Web 应用程序中选择静态和实例数据访问类的优缺点是啥?【英文标题】:What are the pros/cons of choosing between static and instance data access classes in a web app?在 Web 应用程序中选择静态和实例数据访问类的优缺点是什么? 【发布时间】:2011-01-07 02:10:12 【问题描述】:

我已经阅读了有关此主题的其他几个问题(here、here 和 here),但还没有看到很好的答案。我之前开发了相当多的数据访问层,并且个人更喜欢使用实例类而不是静态类。然而,这更多是个人喜好(我喜欢测试我的业务对象,这种方法使模拟 DAL 更容易)。我以前使用静态类来访问数据库,但我一直觉得这样的设计是否合适(尤其是在 ASP.NET 环境中)有点不安全。

关于这两种使用 ADO.NET 提供程序(无 ORM)开发数据访问类的方法,尤其是在 ASP.NET 应用程序中,任何人都可以提供一些好的优点/缺点。如果您还有一些更一般的静态类与实例类提示,请随时提出建议。

我特别关心的问题是:

    线程和并发 可扩展性 性能 任何其他未知数

谢谢!

【问题讨论】:

【参考方案1】:

我的总体感觉是:如果不需要,为什么要实例化?

当不需要多个实例并且不需要实例成员时,我会使用静态类。至于 DAL,关键是只有一个。如果里面没有值,为什么还要实例化呢?

看this link,说明静态方法调用比实例类方法调用快。

This link 表明使用静态类的一个优点是编译器可以检查以确保没有意外添加实例成员。

This link 表明静态类可以用作一组方法的方便容器,这些方法只对输入参数进行操作,而不必获取或设置任何内部实例字段。对于 DAL,这正是您所拥有的。没有理由创建任何内部实例字段,因此也没有理由实例化。

【讨论】:

实例化有很多价值。我个人的感觉完全相反:只有在有令人信服的理由对类型/数据/方法/等进行静态处理时才使用静态。 我的总体感觉是:不需要的时候为什么要让它静态? 主要缺点(我已经看到很多次了):随着时间的推移,事情变得越来越复杂,你最终会得到大的单体方法,因为你的所有状态都必须作为方法参数传递,因为您不能(实际上)使用静态字段在多线程应用程序中存储状态。随着复杂性和深度的增长,人们变得懒惰,而不是将某些东西封装在新方法中,而是内联、复制、粘贴、循环等等。同样的事情也可能发生在实例方法上,但用实例字段重构要容易得多/属性。 @Nitz:这听起来像是不良开发实践和缺乏代码审查的不利因素。 @Gabriel McAdams:除了非常简单的实用程序类(即:System.Math)之外,静态类有很多缺点。它们在线程场景中往往更加困难,因为您需要额外的锁定。它们更难测试,并且在您需要进行复杂测试时模拟出来(对于 DAL 非常重要)。它们不太灵活,因为它们破坏了多态性。基本上,静态类将您锁定在一个固定的、僵化的设计中——在大多数情况下,创建一个非静态类要干净得多。最坏的情况,如果你真的想要静态,考虑一个单例......【参考方案2】:

基于静态的方法通常具有一个,并且只有一个主要优势:它们易于实施。

基于实例的方法赢得:

    线程和并发 - 您不需要任何/尽可能多的同步,因此您可以获得更好的吞吐量 可扩展性 - 与上述问题相同 性能。 - 与上述相同的问题 可测试性 - 这更容易测试,因为模拟实例很容易,而测试静态类很麻烦

静态方法可以取胜:

    内存 - 您只有一个实例,因此占用空间更小 一致性/共享 - 使单个实例与自身保持一致很容易。

总的来说,我觉得基于实例的方法更胜一筹。如果您要扩展到单个服务器之外,这一点变得更加重要,因为一旦您开始在多台机器上实例化静态方法,它就会“崩溃”...

【讨论】:

我认为利大于弊,至少在我看来。至于内存消耗,我认为在大多数应用程序中这可能是一个可以忽略不计的缺点。 @Kevin Babcock:我个人几乎总是尝试使用基于实例的方法。如果我想要/需要静态,我通常会使用单例,因为以后更容易适应多例或实例方法(因为您仍在使用实例......) 为什么一开始在多台机器上实例化静态方法就会“中断”?他们都在自己的内存空间中处理数据。我错过了什么吗?【参考方案3】:

多年来我一直在使用静态 DAL,我同意您的担忧。线程和并发是最具挑战性的,在我的例子中,我将不同的连接对象存储在线程静态结构中。事实证明,它具有很强的可扩展性并且性能良好,现在我将 PropertyInfo 转换为 PropertyDescriptor 更是如此,这为我提供了与反射相同的好处和更好的性能。在我的 DAL 中,我只需要写:

 List<Entity> tableRows = SQL.Read(new SearchCriteria(), new Table());

一切都产生于 SQL 静态类,这让我的代码更简单。

【讨论】:

您的方法遇到了什么样的并发问题? 我设置它的方式是每个线程运行一个连接对象。我必须处理的一个并发问题是当您插入一个新对象,获取其生成的主键(从序列或身份)并填充对象的 PK 值时 - 如果您不小心,您最终会执行许多插入并出错序列搞乱了 FK 关系。【参考方案4】:

对我来说,主要原因是我不需要保留该 DAL 对象的状态。它使用的对象的状态不跨越它们嵌入的方法的范围。这样一来,如果对象的多个实例都相同,为什么还要保留它们?

使用最新版本的 ADO.NET,在调用范围内创建和销毁与数据库的连接似乎是最佳实践,无论如何让 ConnectionPool 处理整个连接可重用性问题。

再次使用最新版本的 .NET Framework,TransactionScope(这将是您自己管理连接的一个原因)提升到业务级别,允许您在同一范围内加入对 DAL 的多个调用。

所以我看不到创建和销毁(或缓存)DAL 实例的令人信服的案例。

【讨论】:

以上是关于在 Web 应用程序中选择静态和实例数据访问类的优缺点是啥?的主要内容,如果未能解决你的问题,请参考以下文章

C#如何封装字段

Java Web 应用程序中的静态层

静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?

14类的静态成员和实例成员

在静态方法中new 一个内部类对象和new 一个外部类对象的区别

Python中静态方法和类方法的区别