我使用一个软件(WMS),其中Oracle PL/SQL包是业务逻辑的重要组成部分。我想介绍一种异步地做一些由事件触发的计算的方法。为了更好地理解,我们将介绍一些运费估算,每当新订单提交到数据库时,都应计算运费估算。重要的是,计算是在另一个会话/线程上进行的,而不是提交订单的原始会话/线程。
我的第一个方法是使用高级队列(AQ)。每当创建订单时,都会有一条消息排队到AQ。然后我得到了三种处理消息的方法(至少我已经想到了):
1.我将使用一个无限DBMS队列作业来创建一个永远运行的作业,它将调用AQ上的出队方法。通过这种方式,作业能够处理消息并进行一些计算。优点:它将立即处理提交的消息。缺点:无限运行的作业不容易停止。
1.使用每X秒运行一次的DBMS作业优点:可以停止作业它不会立即处理消息
1.在AQ上使用触发器来创建新作业这是另一种方法。使用这种方法,我可以创建一个触发器,每当消息排队到AQ时触发。然后,触发器的逻辑将创建一个DBMS队列作业,该作业使AQ和自动丢弃出队。优点:It runs somewhat immediately缺点:数据库将始终创建和删除作业。我不知道这是否是一个问题,但它的胆量感觉这不是很大。
有人有这方面的经验吗?
2条答案
按热度按时间wnavrhmk1#
也许比使用AQ更简单,您可以通过将事件记录插入到(普通)“队列”表中来完成自己的排队,而另一个进程正在轮询它。但是,与其使用调度程序来启动每个轮询事件,不如使用它来启动一个24/7的代理进程,该进程执行一个恒定的循环来轮询,并调用
dbms_lock.sleep
在每个循环中添加一秒左右的睡眠时间,这样就不会占用CPU。我发现这是相当可行的。一个持续运行的进程,如果在开始时由调度程序启动,如果它由于任何原因被杀死,调度程序将自动重新启动。如果在调度程序中设置1分钟的时间间隔,只要进程仍在运行,它就不会做任何事情(它知道自己仍在运行)。但是如果进程死亡(希望是一种罕见的情况),它将在一分钟内重新启动它。当然,你可以把这个窗口缩短。但关键的是,使用
dbms_lock.sleep
进行实际的轮询循环可以让您比使用调度程序更快地完成轮询。如果你需要的话,你甚至可以去次秒。在处理事件之后,您可以删除事件记录或将其状态更新回调用进程(如果需要),然后调用进程可以通过删除记录本身来确认收到状态返回。只要对你最好。
要停止作业,您可以随时简单地调用
dbms_scheduler.stop_job
。要停下来并不难,尤其是在睡觉的时候。0lvr5msh2#
1.我将使用一个无限DBMS队列作业来创建一个永远运行的作业,它将调用AQ上的出队方法。通过这种方式,作业能够处理消息并进行一些计算。优点:它将立即处理提交的消息。缺点:无限运行的作业不容易停止。
虽然事件驱动的工作总是在“倾听”,但这正是关键所在。它们仍然可以被启用/禁用,就像任何其他作业一样。你的第一直觉是正确的,因为这个选项提供了最大的响应能力。
1.使用每X秒运行一次的DBMS作业优点:可以停止作业它不会立即处理消息
正如您已经注意到的,所有这些都引入了滞后时间。除此之外,备选方案1和2在实际上没有区别。仍然可以以相同的方式启用和禁用作业。
1.在AQ上使用触发器来创建新作业这是另一种方法。使用这种方法,我可以创建一个触发器,每当消息排队到AQ时触发。然后,触发器的逻辑将创建一个DBMS队列作业,该作业使AQ和自动丢弃出队。优点:It runs somewhat immediately缺点:数据库将始终创建和删除作业。我不知道这是否是一个问题,但它的胆量感觉这不是很大。
在应用程序逻辑中使用动态扩展几乎总是一个坏主意。它混淆了代码的功能,增加了不必要的复杂性,并且通常被认为是一种安全风险。