基于特定条件ON UPDATE更新另一个表的最佳方法是什么?

时间:2016-09-11 13:14:29

标签: mysql

我有两张表subscriptionsubscription_eventsubscription_event可以是以下类型之一:

public enum SubscriptionEventType {

    CREATED,
    CANCELED,
    CHARGED_SUCCESSFULLY,
    CHARGED_UNSUCCESSFULLY,
    EXPIRED,
    TRIAL_STARTED,
    TRIAL_ENDED,
    WENT_ACTIVE, // Subscription went active and can be charged from now on.
    WENT_PAST_DUE;

    public Long getValue() {
        return this.ordinal() + 1L;
    }
}

我想要做的是将subscription的状态保持为最近的事件。问题:这些事件的顺序不正确。例如。在 CHARGED_SUCCESSFULLY事件之前,可以获得WENT_ACTIVE事件

所以有几种方法可以实现我的需要。首先,我可以检查应用程序层中的条件,并始终根据事件的时间戳设置“最近”状态。

Long subscriptionId = lastRecordedEvent.getSubscriptionId();

if(event.getTimestamp() > lastRecordedEvent.getTimestamp()) {
    // Since the current event is more recent than all other events
    // we also have to update the subscription state
    subscriptionRepository.updateState(subscriptionId, event.getTimestamp());
}

但是,我不希望在我的应用程序层中执行此操作。另一种解决方案是在TRIGGER表上使用subscription_event,然后决定是否更新相关的subscription。我之所以不这么做的原因是因为我知道触发器很容易被遗忘,也很难维持。另外我知道在使用TRIGGER之前应考虑其他所有选项,但由于我不是SQL / MySQL专家,所以我不知道我的所有选择。

那么在这种情况下保持subscription最新的最实用方法是什么?

1 个答案:

答案 0 :(得分:1)

将您的活动照常插入表中,然后执行以下

UPDATE subscriptions set state=events.state
FROM subscriptions inner join events on subscriptions.id = events.subscriptionID
Where events.SubscriptionId = ? and events.Timestamp = 
   (select max(timestamp) from events where events.SubscriptionId = ?)

您需要将两个?的参数传递为刚刚插入的事件的订阅ID

修改

另一种方法是在数据库中使用状态字段,为订阅创建视图,并始终查询视图。

CREATE VIEW vw_subscriptions as
  Select s.id, otherfields from subscription, coalesce(e.Status, 1) as status
  from subscriptions s left outer join events e on s.id=e.subscriptionId
  AND e.timestamp = 
   (select max(timestamp) from events where subscriptionId=s.id)

如果您担心忘记/维护SQL或触发器,请将它们记录为存储库函数中的注释,并将对数据库的所有更改作为与源代码一起存储的更改脚本进行维护。这样你的更改就在你的源代码控制中。