在代码中引用静态数据库数据的最佳方法?


24

许多应用程序都包含“静态数据”:这些数据在应用程序的生命周期中实际上并没有改变。例如,您可能有一个“销售区域”列表,该列表可能是在可预见的将来的固定列表。

在数据库表中找到此静态数据并不罕见(通常是因为您想在其他表的外键中引用它)。一个简单的示例表将具有一个ID(用作主键)和一个Description(描述)。例如,您的SalesArea表将具有(至少)一个SalesAreaId列和一个SalesAreaDescription列。

现在,在代码中,您可能不想将表的每一行都一样。例如,您可能想要在某些屏幕上设置默认的“销售区域”,为某些区域提供不同的数字,或限制用户在其他区域中可以执行的操作。

在代码中引用此静态数据的最佳方法是什么?为什么?

  1. 在代码中硬编码描述。需要时,使用它可以从数据库中查找SalesAreaId。
  2. 将ID硬编码在您的代码中。在需要时使用它来查找SalesAreaDescription。
  3. 为每种目的在表中添加一列,例如“ IsDefaultOnProductLaunchScreen”列,依此类推(可能有很多)。
  4. 还有别的

处理静态数据库数据时,我还应该考虑其他一些特殊因素吗?例如,给这些表起一个特殊的名字?


1
可能的重复:programmers.stackexchange.com/questions/304169/… 我相信关于(链接的)问题的答案会更好地成为IMO的问题
JoeCool

Answers:


14

当应用程序启动时,如何将它们加载到缓存(通常实现为哈希表)中?如果这样做,那么您甚至不必查询数据库(嗯,不止一次)。

我还建议避免对任何内容进行硬编码。为需要默认值的屏幕添加默认指示符(最初在DB表以及高速缓存结构中)。要在非默认状态下进行查找,请尝试将要查找的密钥存储在配置文件或属性文件中。


缓存固然很好,但是如何更新这些值?大概是应用程序重启,还是某种缓存失效策略?
史蒂夫

1
@Steve是的,完全正确。取决于应用程序。重新启动有利于频繁启动。对于长时间运行的应用程序,也许每天在缓慢的时间重新加载缓存一次。我的问题是,应用程序运行时间非常短的情况如何?例如,可能是PHP脚本或类似的东西。
tylermac 2011年

数据库将为经常访问的数据运行其自己的缓存,因此您将重新实现已实现的内容(可能不是那么好!)
James Anderson

@JamesAnderson:缓存应用程序中的手段只会永远是一个调用数据库。是的,数据库将具有自己的缓存,但是那些缓存可能会由于应用程序控制范围之外的事件而无效/刷新,并且您仍然必须与数据库建立连接并进行查询以获取该数据(并希望将其保存在数据库中)。 db的缓存)。实施简单的应用程序内缓存确实并不难。
FrustratedWithFormsDesigner 2013年

7

DB或硬编码的替代方法是使用在启动时读取的配置文件。然后,您可以将这些数据存储在代码中的只读结构中。

在极少数(但并非并非不可能)的情况下,您必须编辑该数据才能重新启动应用程序。如果无法做到这一点,则可以编写一个更复杂的配置管理器,该管理器每次访问数据时都会检查配置文件中的更改,这实际上非常有效,因为您只需要检查文件上的时间戳,然后使所有数据无效如果文件已更新。


1
对于某些类型的静态数据,这是个好主意,但如果您要按照问题中所述的那样来加强FK关系,那就不好了。
克拉美(Kramii)恢复莫妮卡(Monica)2011年

问题没有说这是一个要求,只是一个场景。如果不需要,则配置文件方法效果很好。
史蒂夫

您是对的,我还不够清楚。但是我很高兴……因为我从您的回答中学到了一些东西。我以前从未遇到过这种方法。
克拉米(Kramii)恢复莫妮卡(Monica)2011年

3

如果数据与数据库中的现有数据相关,那么将其添加到数据库中的效率可能与将其添加到代码中一样有效。如果不是,那么我通常很想“把那颗子弹收起来”,并将其放入代码中,直到第一次更改为止。

通常,我们认为是静态的并不是事实,当这种情况发生时,您不必等待代码发布就可以进行更改。一旦发生这种情况,将其放入数据库中并编写一个管理员页面以进行进一步的更新。

以您的示例为例,如果数据库中已经有“销售区域”,请在其中添加说明,而不要构建哈希表以将数据库数据与硬编码列表相关联。但是,如果您不是一定要建立Sales Area的哈希表,而是准备好了,那么当有人第一次更改描述或添加新的Sales Area时,请将其移至数据库。


“通常我们认为静态的结果并非如此”-如此真实。
克拉美(Kramii)恢复莫妮卡(Monica)2011年

3

为什么不只是硬编码所有内容?我一直遇到的主要问题是在应用程序代码中引用数据库中的静态值。如果您只是直接构建下拉列表或静态值之外的东西,那是一回事,但是如果某些应用程序逻辑依赖于数据库中的值怎么办?

在一个简单的应用程序中,我目前有一个内容编辑状态列表:草稿,已发布,已存档。

根据内容项所处的状态,需要对它们进行不同的处理。如果我将状态数据分别保存在DB中,其值分别为1、2、3,那么我将如何检查草稿中是否有内容州?

if (content.State == 1)
还是
if (content.State == "Draft")

我只是对值进行了硬编码!
如果使用缓存/哈希表,也是一样:仍然必须使用代码中写入的某些值 作为查找数据的键。

硬编码方式有哪些缺点?


缺点是如pdr所说:“通常我们认为静态的东西并非如此”。
tylermac 2011年

2
但是,如果您实际上是在代码中引用静态数据值,则无法在不破坏应用程序的情况下在数据库中对其进行更改。可以确定的是,这取决于数据的用途:如上所述,如果它只是填充UI元素,以便用户可以选择一个值,然后将该值作为另一个表中记录的一部分直接传回DB。 ,则数据库中的静态数据可以独立于应用程序代码进行更改。我很确定@pdr正在谈论这种情况:该应用程序将一组静态数据作为单个项目处理。
戴夫

2

与FrustratedWithFormsDesigner所说的类似,这通常是通过缓存完成的,因为这意味着您只需要加载一次静态数据,但是它遵循OAOO模式,这意味着我们不会在两个地方(数据库和数据库)中定义数据。您的代码)。

我知道NHibernate ORM通过第二级缓存提供了此功能。您可以告诉它缓存特定表中的数据,并说它是只读的。它将在第一次需要时加载,即使您从多个会话访问数据,也不会在以后再次访问数据库。


+1一次,只有一次。但是如何不同地对待不同的行呢?
克拉米(Kramii)恢复莫妮卡(Monica),2011年

1
@Kramii-您可以使用类似枚举类的东西。如果元数据仅与您的程序有关,则将业务逻辑(IsDefaultOn...)放在实体的属性中。使其对一个实体返回true。给定整个集合,这将使您能够找到该实体。或者,您可以使用控制器类,该类将为您提供适当的方法调用实体。
Scott Whitlock

2

最糟糕的是过早的优化。

首先,任何现代的DBMS都将以闪电般的速度从小表中检索数据,并且它们的缓存算法范围从良好到精湛(您为DBMS支付的费用越多,缓存就越好!)。因此,您正在优化消耗最少资源的东西。

其次,如果您想像“销售区域”之类的东西是静态数据,那么您对现实世界中的业务应用程序的经验很少。市场总监或首席执行官的每一次变动都可能导致这些变化。因此,您将面临两年的痛苦世界。

这里只有两种方法:

将其存储在数据库中,并使用“普通” sql访问数据。

将其存储在精美的XML配置文件中(可能通过REST或SOAP访问),只要“策略性策略变更”就可以轻松地对其进行编辑。


1

这取决于您对数据的处理方式。如果它是某物的列表,我通常会将其放入数组。如果列表需要在另一个版本中增长,则只需添加到数据库并更改代码以处理数组中的额外数据就很容易了(根据代码,这甚至可能不是必需的,例如,使用for循环使用数组的上限)。如果是设置列表,我通常会用硬编码,因为通常没有很多,并且比使用SQL语句更容易,更快捷。如果这是用户可以更改的设置,并且我想保存选择以便以后启动,我将创建一个表用作注册表,并根据需要将单个条目拉到变量中。


1

我知道这个答案已被接受,但我想分享我在上一个Web开发商店中如何做到这一点,在该商店中我们试图尽可能减少数据库I / O。

我们在服务器端包含文件中使用了尽可能多的查找类型数据结构。主要是用于网站导航(包括子导航),但我们还将它用于尽可能多的下拉菜单和复选框(州,国家/地区,类别)。

最初,我们从数据库中提取了所有这些数据。由于我们为客户提供了一个管理窗口小部件,因此他们可以随意更改此数据,而且我们从来不会陷入很小的小问题。在大多数情况下,这些数据几乎从未更改过,但有时会更改。

我们一直在寻找更快的加载时间。因此,我们决定实现尽可能多的静态服务器端文本文件。我们是在管理小部件旁边完成的。每次更新数据库表时,我们都会重新生成相应的静态文本文件。这给了我们一个非常灵活和快速的环境。


0

我可能无法在所有情况下都有效的解决方案是将静态数据库数据绑定到硬编码的enum。由于问题来自将动态数据(数据库)绑定到静态逻辑(代码),因此,通过使数据库表关联到enum。例如:

LooseDBCodeBinding (database table)
   ID : Int32 (key)
   Name : String
   HardCodedTypeID : Int32

// in code:
public enum LooseDBCodeBinding
{
   TYPE_1 = 1,
   TYPE_2 = 2,
   TYPE_3 = 3 // etc...
}

然后编写一个UI,使您可以轻松查看LooseDBCodeBinding记录列表,并将它们映射到LooseDBCodeBinding enum值(包括支持“断开”绑定)。然后enum,您可以围绕进行编程,并围绕table键设计数据库,而只有一张表同时具有这两种上下文的知识。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.