在 Spring 中设计积分系统
Posted
技术标签:
【中文标题】在 Spring 中设计积分系统【英文标题】:Designing a point system in Spring 【发布时间】:2012-07-26 08:13:00 【问题描述】:我的数据库中已有大量现有数据,并希望开发一种积分机制,根据每个用户的操作计算他们的分数。
我正在以可插入的方式实现此功能,因此它独立于主逻辑,并依赖于在实体被修改后发送的 Spring 事件。
问题在于如何处理现有数据。我不想从现在开始收集积分,而是包括到目前为止的所有数据。
最实用的方法是什么?我是否应该以提供 index() 方法的方式设计我的插件,这将迫使我的系统从数据库中获取每个实体,发送一个 EntityDirtyEvent,为每个插件触发点插件,然后更新它,让积分保存在每个实体旁边。这可能会导致大量开销,对吧?
最简单的方法是创建一个复杂的存储过程,然后让 index() 调用该存储过程。然而,这在我看来也是一件坏事。既然无论如何我都必须在java中编写计算点的逻辑,为什么还要在SQL中再次使用它呢?另外,总的来说,我不喜欢将业务逻辑拆分到不同的层。
以前有人做过吗?请帮忙。
【问题讨论】:
【参考方案1】:首先让我们区分实现策略和业务规则。
由于您已经拥有数据,请考虑直接从数据中获取结果。这形成了数据域模型。设计数据模型以存储所有数据。然后,创建一组查询、视图和存储过程来访问和更新数据。
获得这些视图后,使用 Spring JDBC Template 等数据访问库来获取这些数据并将它们表示为 Java 对象(列表、地图、人员、点表等)。
无论系统的上层发生了什么,到目前为止,您已完成的内容并没有太大变化。这称为模型。
然后,开发一个规则库或逻辑实现,以确定在哪些输入、用户操作、数据条件或所有其他条件下需要哪些数据。在数学意义上,这就像一个矩阵。在编程意义上,这将是一组逻辑语句。如果这个和这个和这个是真的,那么获取这个数据,否则获取那个数据,等等。这包含了你系统中的逻辑。因此它被称为“控制器”。
不要将此逻辑移动到查询/存储过程/视图中。
然后最终为此开发一个前端或“控制台”。在最简单的情况下,开发一个控制台输入系统,它接受一个 .. 并显示一组结果。这是您对系统的“视图”。
您最终可以将视图开发为 Web 应用程序。上面的命令行视图仍然可以以 Restful API 服务器的形式存在。
【讨论】:
【参考方案2】:我认为这里需要考虑一个问题:据我所知,数据库中有大量数据,因此仅创建一种机制来计算积分系统的想法可能不是最佳方法。
事实上,如果您不想开始收集积分,但要包含所有数据,您必须处理和计算您现在拥有的信息。是的,第一次运行可能会产生开销,但正如您所说,您需要计算此数据。
另一方面,您可以包含另一种机制来处理实体中的更改并启动能够计算适用于此特定修改的新指向差异的不同进程。
因此,您可以使用一种服务来负责计算指向系统,一种用于单个实体,另一种可能需要更长的时间才能完成,能够计算全局点。甚至,如果您不需要实时计算,您可以创建一个计划作业来负责启动它。
最后,我知道将业务逻辑拆分为两层(Db + Java)不是一个好方法,但有时需要这样做,例如,如果您需要快速回复最终使用很多注册表。我发现在某些情况下,除了将业务逻辑添加到数据库(作为存储过程等)来管理大量数据并将最终结果返回给浏览器客户端(例如:特定时间的计算过程)之外,别无选择)。
【讨论】:
【参考方案3】:您似乎正朝着正确的方向前进。您知道您希望您的“积分”事物与主应用程序分离。由于暗示您已经在使用休眠(通过标签!),您可以利用休眠事件系统(请参阅here 第 14.2 节)。根据系统的大小/复杂性,您可以在此处插入积分计算(如果它不是大型/复杂系统),或者您可以发布自己的事件以供任何正在侦听的软件接收。
这两种设计方法的关键在于,既不知道也不关心您的积分计算。如果您像我猜测的那样尝试创建一个相当通用的插件机制,那么您可以从这个连接点将您自己的事件发布到该系统。然后,如果您在给定的安装/设置中没有插件,则没有人获取/处理事件。如果您在另一个安装/设置中有多个插件,那么它们每个都可以根据收到的事件决定他们需要进行的处理。在“积分插件”的情况下,它会计算它的积分值并存储它。不需要存储过程....
【讨论】:
【参考方案4】:您正在尝试完成“引导”。您选择的方法应取决于点计算的复杂程度。如果存储过程或普通更新语句是最简单的解决方案,那就这样做吧。
如果计算很复杂,请编写一个批处理作业来加载您现有的数据,可能首先对其最旧的数据进行排序,然后触发与该数据对应的事件,就好像它们刚刚发生一样。处理事件的代码应该与处理未来事件的代码完全相同,因此除了批处理作业本身之外,您无需编写任何其他代码。
既然你只打算运行这个东西一次,那就选择最简单的解决方案,即使它又快又脏。
【讨论】:
【参考方案5】:有两种不同的方式。 一是您已经知道 - 轮询数据库以获取更改的数据。在这种情况下,您可能会在没有更改的情况下访问数据库,并且可能会减慢您的流程。
第二种方法 - 每当数据库发生更改时,数据库将触发该事件。您可以使用 CDC(更改数据捕获)。它将最小化开销。
您可以在Spring Integration寻找更多选项
【讨论】:
以上是关于在 Spring 中设计积分系统的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring Boot 中设计两个单独的授权/身份验证配置?