如果不看示例,很难理解您所描述的内容。但听起来您说的是一种数据库设计反模式,通常称为One True Lookup Table。
CREATE TABLE Parameters (
key VARCHAR(20) PRIMARY KEY,
value VARCHAR(255) NOT NULL,
);
这种设计的问题包括:
您不能使用最适合的 SQL 数据类型,因为value 列必须容纳整数、日期、字符串——所有可能的参数类型的所有值。
您不能使用约束来限制给定参数类型的值。例如,您可能需要一个确保邮政编码符合特定模式的 CHECK 约束。但是你不能,因为所有类型的所有参数都必须符合相同的模式。
您不能将此表用作查找表来约束其他表。例如,如果您希望另一个表中的 country 列引用国家/地区列表并且不允许其他值。通过将所有查找数据存储在同一列中,您的 country 列可以引用任何参数类型的任何值。没有国家/地区'M' 或'F',但您的数据库将允许country 引用它。
无论如何,您都无法创建真正的FOREIGN KEY 约束,除非Parameters.value 列上有UNIQUE 约束,因为'M' 可能是“男性”或“中号衬衫尺寸”,因此在参数表中出现两次。
您根本无法保证给定的键存在,因为无法强制表包含具有特定主键的行。这就是NOT NULL 在传统数据库设计中的用途,其中参数属于列,而不是行。
表可能会变大,因此查找正确属于小集合的值会变得低效。您的应用程序配置参数列表与国家和邮政编码等列表一起存储。
尽管 Richard Harrison wrote in his answer to your other question,他错了。 OTLT 是一个糟糕的设计,你会后悔使用它。
另见OTLT and EAV: the two big design mistakes all beginners make
关于您的具体问题:
您认为让 html 包含 Web 应用程序的 pks 是一种不好的做法吗?我认为是,我建议使用 guid 代替 pks。
关于在 Web 应用程序的用户可见层中显示 pk 的最常见警告是,它可以为攻击者提供有关如何处理部分数据的信息。听起来您仍在 Web 应用程序中显示 pk 值,但您只是将 GUID 换成了整数。我看不出这有什么更好的。
更新:需要明确的是,如果您的代码允许用户通过知道 PK 值来执行非法操作,那么如果用户知道映射到 PK 值的某个代理值,它也将允许相同的非法操作。您没有使用代理值添加任何保护。
那么有必要“冒险”吗?可以做些什么呢?
Defensive programming. 不要假设用户只会点击为他们提供的链接,他们可以编辑链接以指定其他一些 pk 值并提交。攻击者擅长这种事情。
例如:
http://www.example.com/change-password.php?account_id=12345&new-password=xyzzy
您的 PHP 脚本应检查当前用户的会话是否已登录到有权更改帐户 12345 密码的帐户。不要仅仅认为没问题,因为 Web 应用程序不会向用户显示链接去做他们没有特权做的事情。即使应用程序是正确的,攻击者也可以将值更改为他们想要的任何值,然后提交。
您必须在您的应用中编写代码来检查用户是否有权使用他们请求的数据,假设他们可以请求数据,即使他们没有查看数据的权限。如果你能做到这一点,就可以降低暴露 pk 值的风险。
更新:隐藏 PK 值是security by obscurity,这不是有效的安全策略。您的代码需要检查用户是否有权查看或更改该 PK 的记录。如果您正确执行此操作,则攻击者在尝试执行不应执行的操作时会收到“拒绝访问”错误。
如果您的程序员犯了错误,那么构建您的应用程序以假设用户没有权限,并要求程序员编写代码以在每种类型的操作之前建立授权。
另外,使用代码测试来验证用户只有在他们拥有正确的权限时才能调用给定的任务,并且非特权用户不能调用该任务,并且他们会收到适当的错误消息。要求程序员为他们接触的任何功能编写测试。
我确实更喜欢只有一个包含所有参数的表和一个带有键的列,以便从上层引用它们。
没有。 OTLT 是一个糟糕的设计。见上文。
您如何看待具有与参数表相同信息的源文件?我见过一些项目的源代码,每个 pk 都与参数相关......这是一个好习惯吗?
没有。将参数存储在数据库中的目的是,您可以通过访问数据库来更新它们,并且它们会在使用该数据的其他页面中自动生效。如果您无论如何都必须更新代码以使用新值,那么将参数存储在数据库中没有任何好处。如果是这样,您最好将值 only 存储在代码中。
关于带有参数数据的源代码:那么如何从客户端代码中引用特定的prm?假设我在业务层中有一些关于使用 prm 数据工作的性别的逻辑......如何关联这两个数据(我曾经创建常量表)?我想我至少需要一个在 BL 硬编码的密钥......
我猜你对所有事情都使用代理键......
你知道how to use JOINs in SQL吗?您可以将表连接到查找表并搜索值而不是其代理键。
SELECT ... FROM People JOIN Genders USING (gender_id) WHERE gender = 'M'
对于查找表,我喜欢使用自然键。然后您可以搜索值 'M' 而不是该值的代理键。
SELECT ... FROM People WHERE gender = 'M'
您认为创建缓存方案来保存参数数据是否相关?
是的。参数数据可能很少更改,您的性能可以从减少应用程序用来获取它们的查询数量中受益。更新值时,使缓存中的相应条目无效。