值列表:代码常量还是数据库?

13

我想知道是否有关于列表值管理的良好实践。例如,我有一个名为logs的数据库表如下:

---------------
| logs        |
|-------------|
| id          |
| idLogType   |
| message     |
| date        |
---------------

我的问题是关于“idLogType”字段。我知道枚举不是处理这种类型字段的好方法,因为如果我想添加新值,我必须修改表结构。所以我打算创建一个值列表。

您有什么建议来处理值列表吗?

1. 只使用PHP常量?

class LogTypeValues {
  const LOGTYPE_CREATION = 1;
  const LOGTYPE_EDITION  = 2;
  const LOGTYPE_DELETION = 3;

  private $_logTypes = array();

  public function __construct() {
    $this->_logTypes[self::LOGTYPE_CREATION] = "Creation";
    $this->_logTypes[self::LOGTYPE_EDITION]  = "Edition";
    $this->_logTypes[self::LOGTYPE_DELETION] = "Deletion";
  }

  public function getId($logType) { ... }
  public function getLogType($id) { ... }
}

$request = $pdo->prepare('INSERT INTO logs SET idLogType = :idLogType, ...');
$request->execute(array('idLogType' => LogTypeValues::LOGTYPE_CREATION));

2. 只使用数据库吗?

------------
| logTypes |
------------
| id       |
| logType  |
------------
<?php
$request = $pdo->prepare('INSERT INTO logs SET idLogType = 1, ...');
$request->execute(array());

3. 在数据库中同时使用PHP常量?

------------
| logTypes |
------------
| id       |
| logType  |
------------
class LogTypeValues {
  const LOGTYPE_CREATION = 1;
  const LOGTYPE_EDITION  = 2;
  const LOGTYPE_DELETION = 3;
}

你对这三种方法有什么想法?

5个回答

5

我最喜欢的解决方案是:

将日志类型存储在数据库中:

CREATE TABLE logTypes (
    id (SMALLINT, PK)
    code VARCHAR(32) UNIQUE    
) 

在代码中创建常量
class logTypes {
    const CREATE_USER = 1;
    const EDIT_USER = 2;
    ...
}

并选择同步策略:

  • 从数据库创建logTypes类 => 该代码是“数据库的缓存”,如果未生成缓存,则项目将无法正常运行
  • 从代码创建数据库 => 数据库仅对SQL报告和将SQL功能应用于日志类型搜索等有用

例子:

SELECT * FROM logs JOIN logTypes USING logtype_id WHERE logType LIKE "% CREATION"

3

这是一个很好的问题 - 合理的人会有不同的意见,这取决于你对“好”的定义。

选择1可以使PHP很好地工作,但意味着当您想查询日志时,您需要在两个位置使用常量 - 通常,日志查看器不是与日志编写器相同的应用程序。您还必须编写一些自定义逻辑来将数据库中的整数转换为人类可读的字符串。如果有多个应用程序写入日志数据库,则在它们之间保持常量同步变得很重要 - 如果应用程序1认为logType 1 =“用户错误”,而应用程序2认为它是“系统错误”,整个事情就会崩溃。

选项2面临相反的问题 - 您的PHP代码如何“知道”数据库认为logType 1是“用户错误”?您绝对不希望在PHP代码库中有魔术数字。

选项3从概念上将两个系统保持同步 - 但现在您必须找到一种方法来将数据库与您的PHP常量文件同步。有各种逻辑路线可以做到这一点 - 但没有一条路线是微不足道的。

由于我很懒并担心出现错误,因此通常不使用整数 - 而是从常量文件中将表示日志类型的字符串写入数据库。


通过将字符串存储在数据库中,它甚至不符合第一范式,我认为这是绝对不可接受的。 - The Godfather

3
我也曾数次面临类似的情况。显然,上述所有选项都有其利弊,我也没有下定决心。这就是我找到这个线程的原因。
到目前为止,我的首选方法是使用选项1,即仅在应用程序源代码(PHP / Java等)中存储常量。它的主要优点是减少不必要的数据库访问。尽管你们中的一些人可能会说这很小,但是数据库连接通常是许多Web应用程序的瓶颈。另一个优点是它降低了编程复杂性。
除了在本线程中提到的内容之外,我所做的唯一一件事就是在应用程序源代码和相关的数据库表列注释中添加注释,以相互交叉参考。通过这种方式,我尽力提醒未来的开发人员,如果由于某种原因会有任何更改,他们需要同步这两个位置。

1

更或少不结构化的想法:

  • 您不应该在代码或数据库中使用神奇数字。因此,应避免使用日志类型“1”、“2”等。
  • 您应该在PHP代码中使用常量,并为这些常量赋予有意义的字符串值,而不是数值。
  • 这些字符串值可以直接用作数据库中的logType
  • 因此,在logType列中使用ENUM也是完全合理的。如果要添加日志类型,则需要修改表格...那又怎样?这不是经常发生的事情,您需要修改代码来添加新的常量,并且您应该已经准备好模式迁移代码,使添加新的SQL枚举值变得非常简单。

所以,我认为这是最好的解决方案:

  • 常量,如LogTypeValues::CREATION = 'creation'
  • logType列的类型为ENUM('creation', ...)
  • 模式迁移以处理添加日志类型

1
谢谢您的回答,但请注意,包含日志的表可能是数据库中最大的表之一,而存储varchar(1字节+1字节/字符)而不是tinyint(仅1字节)可能会成为问题。 - benjamin.cohen-solal

0

对我有效的是仅使用数据库,因为在设计后端系统时我倾向于首先处理数据库。

------------
| logTypes |
------------
| id       |
| logType  |
| code     |
------------

id := 生成的数据库ID
logType := 表示常量的全名的varchar(例如"LOGTYPE_CREATION")
code := 代表在代码中快速和简便使用的唯一短名称或别名的varchar(例如"LCR")

在这种情况下,如果这些常量可能不会在您的数据库设计中用于其他关联,请选择纯粹基于代码的方法。但如果它们将来可能出现在关系中,则数据库方法对我来说是最好的选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接