我们想编写一些在某些数据之上工作的业务逻辑规则来构建报告。不确定哪个是最好的将它们存储在数据库 MySQL 中。
它可以有一个规则链,然后是一个结果声明,如上所示。
我们想编写一些在某些数据之上工作的业务逻辑规则来构建报告。不确定哪个是最好的将它们存储在数据库 MySQL 中。
它可以有一个规则链,然后是一个结果声明,如上所示。
对于构建报告,您可以使用任何编程语言转换业务逻辑。并使用数据库数据生成报告。
反对存储在数据库中的业务逻辑
我非常看重表达的力量,我发现 SQL 空间并不是那么富有表现力。使用手头上最好的工具来完成最合适的任务。摆弄逻辑和高阶概念最好在最高级别完成。因此,存储和海量数据操作最好在服务器级别完成,可能在存储过程中。
但这取决于。如果您有多个应用程序与一种存储机制进行交互,并且您希望确保它保持其完整性和工作流程,那么您应该将所有逻辑卸载到数据库服务器中。或者,准备好管理多个应用程序中的并发开发。
资料来源:存储过程中支持/反对业务逻辑的论点
也可以看看:
CREATE TABLE businessRule (
id INT NOT NULL ,
name VARCHAR(32) NOT NULL ,
description VARCHAR(255) NULL ,
statement VARCHAR(255) NOT NULL ,
PRIMARY KEY (id) )
ENGINE = InnoDB;
CREATE TABLE leftOperand (
id INT NOT NULL ,
value VARCHAR(255) NOT NULL ,
PRIMARY KEY (id) )
ENGINE = InnoDB;
CREATE TABLE ruleItem (
id INT NOT NULL ,
businessRuleId INT NOT NULL ,
operator ENUM('if','and','or','not') NOT NULL ,
loperand INT NOT NULL ,
comparator ENUM('<','=','>') NOT NULL ,
roperand VARCHAR(255) NOT NULL ,
roperand_ispercentage TINYINT(1) NOT NULL ,
PRIMARY KEY (id) ,
INDEX businessRule_FK (businessRuleId ASC) ,
INDEX leftOperand_FK (loperand ASC) ,
CONSTRAINT businessRule_FK
FOREIGN KEY (businessRuleId )
REFERENCES mydb.businessRule (id )
ON DELETE CASCADE
ON UPDATE RESTRICT,
CONSTRAINT leftOperand_FK
FOREIGN KEY (loperand )
REFERENCES mydb.leftOperand (id )
ON DELETE RESTRICT
ON UPDATE RESTRICT)
ENGINE = InnoDB;
反对“软编码”业务逻辑的论点如下:http ://thedailywtf.com/Articles/Soft_Coding.aspx
“我们发现自己是软编码的原因是因为我们害怕改变。不是正常的害怕改变,而是害怕我们编写的代码会因为业务规则的改变而改变。这是一种非常愚蠢的恐惧. 软件的全部意义(因此,“软”)是它可以改变它会改变。使您的软件免受业务规则更改的唯一方法是构建一个完全通用的程序,它没有所有业务规则但可以实施任何规则。哦,他们已经构建了那个工具。它叫做 C++。还有 Java。还有 C#。还有 Basic。而且,我敢说,COBOL。
我能给你的只是你应该解决这个问题的方法,而不是答案本身。
设计数据库以存储此类复杂数据的一般方法是设计将它们作为对象保存在内存中的方式,然后尝试相应地设计数据库。毕竟,您将在编程语言中评估规则。过程如下: 首先是类图
然后是时候将其转换为 ERD:
一旦你有一个数据库结构来存储/重新加载你的对象,你可以简单地创建你的类,这样每个对象都负责加载/存储自己。
[更新]
例如,如果要将语句存储a + b * -c
到数据库中,可以将其翻译为以下插入:
-- c
INSERT INTO statement (statement_id) VALUES (1);
INSERT INTO operand (statement_id, type) VALUES (1, 'double');
-- - (minus)
INSERT INTO statement (statement_id) VALUES (2);
INSERT INTO operator (statement_id, type) VALUES (2, 'minus');
-- -c
INSERT INTO binary (operator_statement_id, operand_statement_id) VALUES (2, 1);
-- b
INSERT INTO statement (statement_id) VALUES (3);
INSERT INTO operand (statement_id, type) VALUES (3, 'double');
-- * (multiply)
INSERT INTO statement (statement_id) VALUES (4);
INSERT INTO operator (statement_id, type) VALUES (4, 'multiply');
-- b * -c
INSERT INTO unary (operator_statement_id, operand_statement_id1, operand_statement_id2) VALUES (4, 3, 2);
-- a
INSERT INTO statement (statement_id) VALUES (5);
INSERT INTO operand (statement_id, type) VALUES (5, 'double');
-- + (plus)
INSERT INTO statement (statement_id) VALUES (6);
INSERT INTO operator (statement_id, type) VALUES (6, 'sum');
-- a + b * -c
INSERT INTO unary (operator_statement_id, operand_statement_id1, operand_statement_id2) VALUES (6, 5, 4);
我认为首先需要做的是质疑您是否应该将规则放入数据库中。
数据库是一种繁重的解决方案,通常根本不需要。
在处理过各种形式的规则引擎(包括数据库驱动)之后,我可以告诉你它会很快变得非常令人沮丧和低效。我见过的最大错误之一是尝试编写自己的临时规则语言并使用它来通过数据库驱动条件逻辑。至少,使用已经过验证的语言(Python、javscript 等)并将其嵌入其中。
更好的是——如果规则足够复杂,我个人更喜欢使用 Excel 电子表格。我们将其用于自动化(处理基于生效日期等的可变逻辑),我们还将相当复杂的保险评级逻辑编译为通过 Web 服务接口的 Perl 脚本,使用此产品:http ://decisionresearch.com/products/评级.html。
将逻辑存储在数据库中与 Excel 电子表格进行对比:
当然,您可以想象,Web 服务驱动的 Excel 规则引擎并不适合所有情况。这不是这里唯一可能的解决方案。
不过,我要确保您在可用性/表现力/可测试性/性能方面做出正确的权衡。在我工作的地方,正确和高效比快速执行更重要,因此我们使用 Excel/Web 服务。
并且扩展 slavik262 的评论,您真正希望使用规则引擎最终实现的是抽象和泛化,以最大限度地减少移动部件并提高可靠性、可测试性和可理解性。以我的经验,数据库规则引擎通常与甚至只是简单地制作基于 Java 的规则相比是次优的。只要它们被沙盒化并正确组织,并隐藏在通用且一致的界面后面,那么它们就可以正常工作。
在我的公司,这取决于规则的规模以及它们改变的频率。评级保险-Excel,毫无疑问。一些国家特定的逻辑?接口的 Java 规则文件就足够了。
如果您不需要基于规则的组件执行搜索,那么您可以将规则存储在数据库的两个字段中。语句在一个中执行的条件和在另一个中执行的语句。
id, name, description, condition, statement
您的规则可以使用 JSON 或类似的格式存储。
我需要定义一些我将要使用的术语。有原子术语,系统值与用户输入的值比较,评估为真/假,复杂术语,使用逻辑运算符组合的术语。
在原子术语中,var表示系统将提供的值(例如访问者的数量或唯一访问者的数量)。比较确定如何根据value评估var。该值是用户生成的数字或字符串。当 var 和 value 都是数字时,比较可以是 "<"、"<="、"="、">=" 或 ">"。当 var 和 value 都是字符串时,比较可以是“等于”、“开始于”、“结束于”或“包含”。原子项可以存储如下:
{ var: varName, comp: comparison, value: numberOrString }
您可以使用以下格式存储由连词、析取和否定(和/或/非)组成的复杂术语。
// Conjunction
{ op: "and", terms: [ term, ..., term ] }
// Disjunction
{ op: "or", terms: [ term, ..., term ] }
// Negation
{ op: "not", term: term }
然后,您可以使用这些方法构建评估为真/假的语句。一个例子如下:
{ op: "and", terms: [
{op "or", terms: [
{ field: "numVisitors", comp: ">", value: 1000 },
{ field: "numUniqueVisitors", comp: ">=" 100 }
]},
{ op: "not", term: {
{ field: "numVisitors", comp: "<", value: 500 }
}}
]}
当访问者数量大于 1000 或唯一访问者数量大于等于 100 且访问者数量不小于 500 时,上例等价于 true。
然后,当规则评估为真时,您可以执行您称为“语句”的内容。
因此,如果我理解正确,您希望使用前端来允许人们动态创建将应用于查询的逻辑(在运行时根据正在使用的规则动态构建 where 子句)?
如果是这种情况,您需要非常具体地说明他们可以在规则中选择哪些条件(更改什么值(列),以便他们只能针对您报告的数据集中存在的列使用条件规则)。
如果我正确理解了您的问题,我将首先绘制出您希望他们能够选择条件的表/列。这将是您为网页设计规则的控件。
但是,如果您只是询问在数据库中选择规则后如何存储规则,我建议将其存储在包含以下内容的单个表中:
ID | RuleSetName | Table | Column | Comparison | Value | Percentage | Notes | CreatedDate | Created By
1 | 'VisitorAnalytics' | Visitors | SUM(Views) | > | null | 10 | n/a | 1/1/2012 | JohnDoe
然后,一旦创建了这些记录,您将通过将表注入 from 子句,将列注入动态 sql 的 where 子句来使用它们。
我知道这听起来可能令人困惑,但您要问的是一个相当复杂的解决方案。但最终,您只想将规则一起存储在一个可以循环动态构建然后执行 SQL 以生成报告的地方。希望这会为您指明正确的方向。
一种简单的方法是使用 OODBMS。在那里,方法用槽封装到对象中,它们甚至可以在数据库中执行(如触发器)。
现在如果你坚持使用 SQL 数据库,你可以做的是使用动态编程语言,并有一个表来存储代码,可能与其他表或行相关联。
几年前,我看到了阿尔及利亚政府税收系统的招标,他们计划将业务规则(税收规则)作为 Visual Basic 代码存储在 RDBMS 中。
您可以选择任何可以轻松将解释器嵌入到应用程序中的语言(Common Lisp http://ecls.sourceforge.net;或者http://common-lisp.net/project/armedbear/,如果您使用以下语言编写应用程序Java)、Lua、Javascript、Scheme 等。
它倾向于使用 Common Lisp 或 Scheme,因为使用这些语言,您可以轻松地为业务规则编写 DSL。
给出的示例可以写成符号表达式,例如:
(rule :name "RuleName"
:description "Some description"
:body (if (and (< (change-in total-visitor) (percent 10))
(> (change-in unique-visitors) (percent 2)))
(do-something)))
在 lisp 中,这样的符号表达式可以使用 PRINT 或 PRINT-TO-STRING 运算符以可读的方式打印出来,这样您就可以将此表达式插入 SQL 数据库:
insert into rules (id,expression) values (42,"(rule :name \"RuleName\"
:description \"Some description\"
:body (if (and (< (change-in total-visitor) (percent 10))
(> (change-in unique-visitors) (percent 2)))
(do-something)))");
您可以从 SQL 中获取它,使用 lisp READ 或 READ-FROM-STRING 运算符将其作为符号表达式读回,然后使用正确的 DSL,您可以使用 lisp EVAL 运算符对其进行评估:
;; with the right DSL written:
(eval (read-from-string (sql-select (expression) :where (= id 42))))
我猜测规则的目的是从现有的数据库表(或表)中命名计算字段。否则,仅出于报告目的,您可以将数据转储到 Excel 中,并让用户使用 Excel 函数和数据透视表来实现其目的。
关键问题是你将如何将规则转化为行动。如果目的只是为了存储业务规则,那么就可以创建业务规则报表,那么简单的 SQL 数据结构就足够了。
但是,如果要将规则转化为代码,则需要考虑代码将在何处运行。当数据存储在 SQL 中时,您有多种选择:
我对其中的第一个有偏见。主要原因是它将工具限制为一个:SQL。
我不确定您的规则在做什么;关键是“语句”组件的作用。让我假设这是一个常数或可以计算的数据表达式。在这种情况下,您的规则开始看起来很像案例陈述。需要注意的是,该语句可能需要查看数据表中的多行(以处理随时间的变化)。
我的建议是将这些规则存储在数据库中。此存储将允许您使用 SQL 编码从一系列业务规则构造查询。Mysql 允许动态 SQL(现在)。在不了解基础表和规则的情况下,很难提供更多信息。
我可以说我设计了一个用于场景分析的复杂得多的系统。场景本身存储在电子表格、一系列表格、常量等中——很像您的业务规则。该系统通过使用 SQL(和一些 Excel)将场景的电子表格表示转换为(巨大的)查询来工作。然后它可以运行查询以生成相关的报告。该系统已被证明灵活、高效且功能强大。
使用存储过程的唯一可能好处是可以从使用不同技术(如 Python 和 Java)的应用程序访问数据库。
我想您是否已经记录了现有的业务逻辑规则和要求?.. 这是设计架构、选择最佳客户端开发工具和设计客户端程序和过程的最重要因素。我为我的当铺管理应用程序做了这个。该应用程序的功能完全由表驱动。它具有控制表,管理员可以在其中更改有效参数以修改系统的工作方式。当与结构化编程技术结合使用时,可以最大限度地减少编程代码修改量。银行应用程序也是具有复杂业务规则的一个很好的例子。