我正在使rest-api接收指令列表,服务器上的特定线程应在24小时内执行该指令,将其称为每日计划。在一定的时间间隔内执行相同的指令:
[
{
instructionName: string
args : [
string
...
]
startHh : int
startMm : int
endHh : int
endMm : int
}
...
]
args
的内容因instructionName
而异。
时间表应保存在MySql中。线程每隔x秒应向db请求当前指令并做一些工作。
我的问题是我不确定在数据库中存储指令列表的最佳选择是什么。在我看来,我有两个选择:
使用第一种方法,我要做的就是将concat args
绑定到单个字符串,然后将json直接解析为DTO对象并保留它,我必须小心,不要存储该指令名和参数工作线程稍后无法解释。工作线程可以轻松查询指令表并获取有关时间间隔的当前指令。
在第二种方法中,我必须首先使用指令名找出表,看看args是否对该表有效,然后将其插入。辅助线程无法以简单的方式获取当前指令,因为指令被分隔在不同的表中。当工作线程找出要查询该线程的表时,可以确保将args格式化为正确的格式,因为它们被分为几列。
在我的应用程序中,将会有很多类型的指令,并且在应用程序的生命周期中会不断添加新的指令类型。
似乎这两种方法都存在很大的问题,我无法为我的特定用例找出最佳的方法。我想知道我是否甚至应该为这些类型的数据使用关系数据库。
感谢任何输入。
答案 0 :(得分:2)
在我的应用程序中,将有许多类型的指令和 在生命周期中将不断添加新的指令类型 的应用程序。
选择哪种解决方案取决于您对很多和连续的定义。数据库在查询现有数据方面非常出色。更改存储的数据和添加新数据非常好。更改数据库布局很糟糕。因此,您应该避免更改布局。
如果每天连续更改 次,我不建议为每个应用程序创建一张表。
即使许多应用程序意味着1000个应用程序/参数配置,每个应用程序的表也将导致1000个表,这是非常不希望的。
另一方面,如果您选择第一种方法,那么,正如您所说的,您将必须妥善保存命令及其参数。
如果您有某种可以解决问题的用例的存储库模式,则可以让存储库在将参数存储到数据库之前检查这些参数。
void ScheduleBackupTask(TimeSpan startTime, TimeSpan stopTime, ... <backup parameters>)
{
// check the parameter list, to see if they match the parameters of a backup task
// and create the command
var command = CreateBackupCommand(<backup parameters>);
ScheduleCommand(startTime, stopTime, command);
}
void ScheduleCleaningTask(TimeSpan startTime, TimeSpan stopTime, <cleaning parameters>)
{
// check the parameter list, to see if they match the parameters of a clean task
// and create the command
var command = CreateCleanCommand(<cleaning parameters>);
ScheduleCommand(startTime, stopTime, command);
}
void ScheduleCommand(TimeSpan startTime, TimeSpan stopTime, Command command)
{
using (var dbContext = new MyDbContext()
{
Schedule schedule = new Schedule(startTime, stopTime, command);
dbContext.Schedules.Add(shedule);
dbContext.SaveChanges();
}
}
每次必须支持新命令或更改命令参数时,都必须创建或更改Create...Command
函数。只有一个地方需要检查参数。
即使您选择了第二个解决方案,您也将需要一个可以检查参数并按正确顺序放置它们的函数。因此,您的第二个解决方案将无济于事。
显然,使用第一种方法可以更轻松,更快捷地查询必须执行的命令。提取命令(包括commandType
)后,就很容易执行它:
IEnumerable<Command> commandsToExecute = FetchCommandsToExecute(TimeSpan time);
foreach (Command command in commandsToExecute)
{
switch (command.CommandType)
{
case CommandType.Backup:
ExecuteBackup(...);
break;
case CommandType.Clean:
ExecuteClean(...);
break;
}
}
很明显,当支持新命令时,您将不得不更改开关。但是,在第二种解决方案中,您还必须更改执行功能。
总结:如果您想到许多要支持的命令,请定期 更改参数或支持的命令种类,可能会建议 具有一张包含所有要支持的命令的表。让你 存储库模式在添加/更新/之前检查参数 执行
答案 1 :(得分:1)
当使用率足够低时,任何模型都可以运行。但是,当使用量很大时,诸如{ALTER TABLE“之类的DDL用来添加新的参数,如果不是禁止的话,就变得非常昂贵。表模式应尽可能少地更改。因此,如果我必须在两者之间进行选择,那么我会首选您的第一个选择。
对我来说,它是否足够好取决于您是否真的要查询参数并可能对高度动态的数据进行建模,或者仅是需要放置一些文本并且不特别在意其中的内容。
例如,如果您希望能够回答诸如“ fuelCount
设置为3的特定作业的执行?”之类的问题。对于这种问题,您需要能够从本质上非结构化的文本字符串中找到fuelCount的存在及其值。它将需要不熟练的操守来将分析保留在服务器上,但是除了最小的数据集之外,将每一行都拉回mysql客户端以解析参数同样是站不住脚的。
另一种选择是,如果您的数据库版本支持mysql json features。这样,您就可以根据需要对参数进行建模,而不必在出现新值时更改表格式。但是,您必须足够聪明,以确保在更改模型时旧查询不会中断。 json对mysql的支持意味着能够查询json中的数据,而不必在数据库客户端中检索,解析和聚合所有单独的记录,因此这是一个非常简洁的功能。 Postgres也有它。
例如,您可以在runtime JSON
列中保存有关要运行的命令的任意数据,并且只要遵守一些简单的规则,就可以为所有参数以及其他参数使用可选参数。 (例如)程序可能还需要的环境变量。随着时间的流逝,可能会出现其他运行时设置,迫使您向某些作业添加更多参数。 JSON类型对此非常有用。如果要查询JSON,则可以。这使您可以在数据上施加 some 结构(例如,所有参数都在顶级字典的args
键内),而不必预先定义可能传递的每个参数。
如果您的想法很好,那么在上面的链接中已很好地说明了这一点。您Aready似乎在考虑json之类的东西,因此这可能是一个简单的过渡。这样做的另一个好处是非常易于网络使用,就像您正在构建REST API一样,您可能已经打算交换JSON。
如果您对较旧版本的mysql感到震惊,并且无法摆脱它,或者被查询困扰,我仍然建议您坚持采用第一种方法。如果您想更进一步,可以添加表格
CREATE TABLE args ( instruction_id int, argkey varchar, argval varchar)
,如果group_concat
的最大长度不是限制因素,则使用例如GROUP_CONCAT将它们合并在一起。否则,您仍然可以在运行时将它们串联起来。这对我来说似乎很笨拙,但它会将变量数据保留在行中,并且确实允许您在服务器端查询数据。