更新数据库键,其中一个表的键引用另一个表的键

时间:2018-06-28 20:16:09

标签: database amazon-dynamodb

我在DynamoDB中有两个表。一个拥有关于房屋的数据,一个拥有关于企业的数据。房屋表列出了最接近的商家,并列出了每个商家的步行时间。也就是说,房屋表具有ID列表,该ID引用了企业表中的项目。由于企业在不断地打开和关闭,因此这两个表都需要经常更新。

我面临的问题是,当其中一个表被更新时,另一个表将具有不正确的数据,直到它本身被更新为止。为了更清楚地说明这一点:假设一家公司关门,而另一家店开门。我可以先更新业务表,以删除旧业务并添加新业务,但是房屋表仍将引用现在已删除的业务。同样,如果我先更新房屋表以引用新业务,那么businesss表将还没有该新业务的数据。无论我先更新哪个表,始终都会有一段时间,这两个表不同步。

解决此问题的最佳方法是什么?我考虑过的一种方法是对辅助数据库进行所有更新,然后与主数据库交换它,但是我想知道是否有更好的方法。

谢谢!

1 个答案:

答案 0 :(得分:0)

Dynamo仅在项目级别提供原子操作,而不在事务级别提供原子操作,但是您可以通过在应用程序中执行一些规则来获得与原子事务类似的功能。

假设您需要通过两个操作来运行事务

  1. 从表中删除Business(id=123)
  2. 更新Home(id=456),以从Business(id=123)数组中删除与home.businesses的关联。

这是您模仿交易的方法:

生成用于锁定项目的时间戳

假设我们当前的时间戳为1234567890。使用时间戳可以清除失败的事务(稍后再解释)。

锁定两个项目

同时更新Business-123Home-456并设置属性lock=1234567890

请勿在此更新操作上更改任何其他属性!

在更新之前,请使用ConditionalExpression(检查Developer GuideAPI)来验证attribute_not_exists(lock)。这样,您可以确定没有其他进程使用相同的项目。

处理更新锁定响应

检查两个更新是否都成功更新到家庭和企业版。如果两者都同意,则意味着您可以进行所需的实际更改:删除Business-123并更新Home-456,以删除业务关联。

为格外小心,请在两个更新中再次使用ConditionExpression,但现在要确保使用lock == 1234567890。这样,您可以确保没有其他进程覆盖您的锁。

如果两个更新再次成功,则可以将两个更新且一致的项目视为由其他进程读取。为此,请运行第三个更新,从两个项目中删除lock属性。

其中一项操作失败时,例如,您可以重试X次。如果所有X次都失败,请确保该过程清除了之前成功执行的另一个lock

通过代码强制执行事务锁定

始终在代码的任何部分使用ConditionExpression,这可能会更新/删除家庭和企业项目。这对于解决方案的工作至关重要。

在阅读家庭和企业项目时,您需要这样做(在所有阅读过程中都没有必要,您将决定在阅读项目时是否需要确保从头到尾的一致性。来自数据库):

  1. 检索您要阅读的项目
  2. 生成锁定时间戳记
  3. 使用lock=timestamp使用ConditionExpression更新项目
  4. 如果更新成功,请继续正常使用该项目;如果没有,请等待一两秒钟,然后重试;
  5. 完成后,更新项目,删除lock

定期清理失败的交易

每分钟左右,运行一个后台进程以查找可能失败的事务。如果您的流程最多需要60秒才能完成,并且某个项目的lock值早于5分钟(请记住lock值是交易开始的时间),那么可以肯定地说此交易有时会失败,无论运行什么进程都无法正确清理锁。

此后台作业将确保没有物品永久锁定。

  

请注意,此实现并不能确保传统ACID DB可以做到真正的原子和一致的事务。如果这对您来说是至关重要的任务(例如,您正在处理金融交易),请不要尝试执行此操作。既然您说如果在极少数失败的情况下破坏原子性是可以的,那么您可以快乐地接受它。 ;)

希望这会有所帮助!