在数据库中存储业务逻辑

时间:2012-07-10 05:21:43

标签: mysql database business-logic business-rules segment

我们希望编写一些在某些数据之上工作的业务逻辑规则来构建报告。不确定哪个最好将它们存储在数据库MySQL中。

enter image description here

它可以有一系列规则,然后是结果的声明,如上所示。

11 个答案:

答案 0 :(得分:18)

要构建报告,您可以使用任何编程语言转换业务逻辑。并使用数据库数据生成报告。

反对存储在数据库中的业务逻辑

  

我高度重视表达的力量,我找不到   SQL空间都是富有表现力的。使用您拥有的最佳工具   为最合适的任务提供帮助。摆弄逻辑和更高   订单概念最好在最高级别完成。所以,   存储和海量数据操作最好在服务器级别完成,   可能在存储过程中。

     

但这取决于。如果您有多个应用程序与一个应用程序交互   存储机制,您希望确保它保持其完整性   和工作流程,然后你应该将所有的逻辑卸载到   数据库服务器或者,准备好管理并发开发   多个应用程序。

来源:Arguments for/against Business Logic in stored procedures

另见:

  1. Business Logic in the Database
  2. Business Logic In Stored Procedures
  3. Storing conditional logic expressions/rules in a database

答案 1 :(得分:12)

Model

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;

答案 2 :(得分:12)

反对“软编码”业务逻辑的论据如下:http://thedailywtf.com/Articles/Soft_Coding.aspx

  

“我们发现自己软编码的原因是因为我们担心变化。不是正常的变革恐惧,而是担心我们编写的代码必须因业务规则的变化而改变。这是一个非常愚蠢的软件的全部意义(因此,“软”)是它可以改变它将会发生变化。将软件与业务规则变更隔离开来的唯一方法是构建一个完全没有所有业务的通用程序。规则还可以实现任何规则。哦,他们已经构建了这个工具。它叫做C ++。还有Java。还有C#。还有Basic。而且,我敢说,COBOL。“

答案 3 :(得分:8)

我能给你的只是解决这个问题的方式,而不是答案本身。

设计数据库来存储这样的复杂数据的一般方法是设计将它们作为对象保存在内存中的方式,然后尝试相应地设计数据库。毕竟,您将使用编程语言评估规则。程序如下:首先是类图

Class diagram

然后是时候将其转换为ERD:

enter image description here

一旦你有一个数据库结构来存储/重新加载你的对象,你可以简单地创建你的类,使每个对象负责加载/存储自己。

<强> [UPDATE]

例如,如果要将语句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);

答案 4 :(得分:6)

我认为首先需要做的是质疑你是否应该将规则放在数据库中开始。

数据库是一个沉重的解决方案,通常根本不需要。

以各种形式处理规则引擎,包括数据库驱动,我可以告诉你它真的很令人沮丧和非生产性,非常快。我见过的一个重大错误就是尝试编写自己的ad-hoc规则语言,并使用它来通过数据库驱动条件逻辑。至少,使用已经证明的语言(Python,javscript等)并将其嵌入其中。

更好 - 如果规则足够复杂,我个人更喜欢使用Excel电子表格。我们使用它来实现自动化(根据生效日期处理变量逻辑等),我们还使用此产品编译相当复杂的保险评级逻辑到通过Web服务连接的Perl脚本:http://decisionresearch.com/products/rating.html

对比存储数据库中的逻辑,比如Excel电子表格:

  1. 与Excel相比,数据库中的逻辑更难测试和开发,因为Excel提供即时反馈。
  2. 与Excel相比,数据库更少(更少)表达。
  3. 您可以为Excel添加颜色代码并添加各种其他视觉提示,以使错误条件等真正脱颖而出。
  4. 当然,正如您所想象的那样,Web服务驱动的Excel规则引擎并不适合所有情况。而且这不是唯一可行的解​​决方案。

    我所得到的是确保您在可用性/表现力/可测试性/性能方面做出正确的权衡。在我工作的地方,正确而富有成效比快速执行更重要,因此我们使用Excel / Web服务。

    为了扩展slavik262的评论,你真正想要用规则引擎实现的目标,最终是抽象和泛化,以最小化移动部件并提高可靠性,可测试性和可理解性。数据库规则根据我的经验,引擎在经常比较甚至只是简单地制作基于Java的规则方面是次优的。只要它们是沙盒和组织得当,并隐藏在一个通用且一致的界面后面,那么它们就可以正常工作。

    在我的公司,这取决于规则的规模以及它们变化的频率。评级保险 - Excel,毫无疑问。一些州的具体逻辑?接口的Java规则文件就足够了。

答案 5 :(得分:4)

因此,如果我理解正确,您希望使用前端允许人们动态创建将应用于查询的逻辑(根据使用的规则在运行时动态构建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来生成报告。希望这能指出你正确的方向。

答案 6 :(得分:2)

如果您不需要根据规则的组件执行搜索,则可以将规则存储在数据库的两个字段中。语句在一个语句中执行的条件和在另一个语句中执行的语句。

id, name, description, condition, statement

您的规则可以使用JSON或某种类似格式存储。

我需要定义一些我将要使用的术语。有原子术语,系统值与用户输入的评估为真/假的值进行比较,复杂术语,使用逻辑运算符组合的术语。

原子术语中, var 表示系统将提供的值(例如访问者数量或唯一身份访问者数量)。 比较确定如何根据评估 var 是用户生成的数字或字符串。当var和值都是数字时,比较可以是“&lt;”,“&lt; =”,“=”,“&gt; =”或“&gt;”。当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 }

然后,您可以使用这些方法构建评估为true / false的语句。一个例子如下:

{ 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。

当规则评估为真时,您可以执行您所称的“语句”。

答案 7 :(得分:2)

我猜这个规则的目的是命名现有数据库表(或多个表)中的计算字段。否则,仅出于报告目的,您可以将数据转储到Excel中,并允许用户使用Excel函数和数据透视表来实现其目的。

关键问题是你如何将规则转化为行动。如果目的只是存储业务规则,那么您可以创建业务规则的报告,那么SQL中的简单数据结构就足够了。

但是,如果要将规则转换为代码,则需要考虑代码的运行位置。当数据存储在SQL中时,您有几个选项:

  • 创建将提取“业务规则”结果的SQL代码。
  • 创建一个用户定义的函数,用于解析和执行业务规则。
  • 将数据提取到另一个环境,例如C ++或C#,然后在那里运行代码。

我偏向于第一个。主要原因是它将工具限制为一个:SQL。

我不确定你的规则在做什么;关键是“声明”组件的作用。我假设这是一个常数或可以计算的数据表达式。在这种情况下,您的规则开始看起来很像案例陈述。需要注意的是,该语句可能需要查看数据表中的多行(以处理随时间的变化)。

我的建议是将这些规则存储在数据库中。此存储允许您使用SQL编码从一系列业务规则构造查询。 Mysql允许动态SQL(现在)。在不了解基础表和规则的情况下,很难提供更多信息。

我可以说我设计了一个更复杂的系统用于场景分析。场景本身存储在电子表格中,存储在一系列表格,常量等中 - 就像您的业务规则一样。该系统通过使用SQL(和一些Excel)将场景的电子表格表示转换为(巨型)查询。然后,它可以运行查询以生成关联的报告。该系统经过验证,具有灵活性,高性能和强大的功能。

答案 8 :(得分:1)

一种简单的方法是使用OODBMS。在那里,方法用插槽封装到对象中,甚至可以在数据库中执行(如触发器)。

现在,如果你坚持使用SQL数据库,你可以做的是使用动态编程语言,并有一个表来存储代码,可能与其他表或行相关联。

几年前,我看到阿尔及利亚政府税务系统的招标,他们计划将业务规则(税收规则)存储为RDBMS中的Visual Basic代码。

您可以选择任何语言,您可以轻松地将解释器嵌入到您的应用程序中(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运算符对其进行评估:< / p>

;; with the right DSL written:
(eval (read-from-string (sql-select (expression) :where (= id 42))))

答案 9 :(得分:0)

使用存储过程的唯一可能好处是可以从使用不同技术的应用程序(如Python和Java)访问数据库。

答案 10 :(得分:0)

我认为您已经记录了现有的业务逻辑规则和要求?这是设计架构,选择最佳客户端开发工具以及设计客户端程序和过程的最重要因素。我为我的Pawnshop Management应用程序做了这个。应用程序的功能完全由表驱动。它具有控制表,管理员可以在其中更改有效参数以修改系统的工作方式。与结构化编程技术结合使用时,可以最大限度地减少编程代码修改的数量。银行应用程序也是具有复杂业务规则的一个很好的例子。

相关问题