对汇票/货币兑换类型的Web应用程序建议的数据库结构的反馈

时间:2019-06-13 18:44:30

标签: sql database postgresql database-design

我并不是真正的数据库专家,因此,我希望就以下建议的数据库结构提供一些反馈。情况如下;我正在构建一个Web应用程序,访客可以在其中以某种货币下达汇票,并以另一种货币接收等值的货币。管理资金的钱包不是数据库结构的一部分,它们通过在本地网络上运行的API进行通信。我需要在数据库中管理的唯一一件事就是订单及其相关的金额。这里有几件事:

  1. 如果订购的金额大于单个钱包的当前余额,则可能需要将所请求的订单金额分散到多个钱包中。
  2. 在闲置15分钟后,订单会自动过期(也就是说,订购者需要在下订单后的15分钟内确认订单)。确认过程与我的问题无关,因此将省略详细信息。
  3. 我不知何故需要保持属于当前标记为未完成(即状态为“新”,“待处理”等,但不是”的订单的所有订单金额的总和)过期”,“失败”,“完成”)。
  4. 钱包余额与第3点的运行金额之间的差额将告诉我,钱包是否有足够的可用资金来支付接单。
  5. 在确定是否可以下订单(通过上一步)并实际下订单(全部作为单个数据库事务的一部分完成)的过程中,金额所涉及的行表需要锁定,以避免潜在的并发问题。

到目前为止我想出的数据库结构:

订单表
+-------------------+------------+-----------+---------------------+---------------------+
| id                | rate       | status    | created_at          | updated_at          |
+-------------------+------------+-----------+---------------------+---------------------+
| 8ec17086-0d34-... | 0.00024041 | "expired" | 2019-12-06 20:11:30 | 2019-12-06 20:26:30 |
| 4fcaf220-c3af-... | 0.00026243 | "new"     | 2019-13-06 15:01:50 | 2019-13-06 15:01:50 | 
| ...               | ...        | ...       | ...                 | ...                 |
金额表
+-----+--------+------------+-------------------+
| id  | value  | wallet     | order_id          |
+-----+--------+------------+-------------------+
| 1   | 150000 | "wallet_2" | 8ec17086-0d34-... |
| 2   | 100000 | "wallet_1" | 4fcaf220-c3af-... |
| 3   | 200000 | "wallet_3" | 4fcaf220-c3af-... |
| ... | ...    | ...        | ...               |

计算/跟踪未结订单金额的总和的方式我仍然不确定,基本上是我希望听到一些不同的事情。我自己已经考虑过以下选项:

  1. 每次收到新的汇票请求时,都会动态计算每个钱包的运行总和。类似这样:

    SELECT SUM("amount"."value") AS "sum" FROM "amount" "amount" INNER JOIN "order" "order" ON "order"."id"="amount"."orderId" AND ("order"."status" IN ("new", "pending", "accepted")) WHERE "amount"."wallet" = "wallet_1"
    

    专业人士:

    • 最容易实现,因为我不需要做任何进一步的记账。

    骗子

    • 效率不是最高,因为您每次都必须计算总和。如果未完成订单的数量不太大,可能不会成为问题。
    • 我无法锁定行(请参见第5点),因为在涉及聚合函数时, PostgreSQL 不允许锁定。
  2. amount 表中添加一个额外的 balance 列,该表用于存储累积金额。每次我想了解订单余额时,我都只查找与未完成订单相关的最新订单金额。因此, amount 表如下所示:

    +-----+--------+---------+------------+-------------------+
    | id  | value  | balance | wallet     | order_id          |
    +-----+--------+---------+------------+-------------------+
    | 1   | 150000 | 150000  | "wallet_2" | 8ec17086-0d34-... |
    | 2   | 100000 | 250000  | "wallet_1" | 4fcaf220-c3af-... |
    | 3   | 200000 | 450000  | "wallet_3" | 4fcaf220-c3af-... |
    | ... | ...    | ...     | ...        | ...               |
    

    专业人士:

    • 从理论上讲,这似乎是最优雅的解决方案,但它带有复杂性。

    骗局:

    • 当订单的状态不再显示为未完成(例如“新”,“已接受”)时,情况将变得复杂。订单在某个时候将从未决状态(“新”,“已接受”等)转换为未决状态(“已完成”,“已拒绝”,“已到期”等)。在这些情况下,需要对整个余额历史进行修订。因此,这实际上是行不通的。
  3. 添加一个新表,该表的行和列与记录每个钱包的订单金额总和的钱包一样多。每次创建订单时,对应的列都需要增加订单金额,每次订单完成,到期或以其他任何方式从未完成状态转换为未完成状态时,相关列都会减少相关订单金额代替。我猜这也可能是多行(每个钱包单独一行)和单列表。考虑一下,这样做会更有意义,因为在添加/删除钱包时会更加灵活。

    专业人士:

    • 这从前两个选项中规避了骗局。

    骗局:

    • 单行单列表对我来说似乎不是一个非常优雅的解决方案,但是也许我不应该让这影响我的决策。

我试图尽可能简洁地描述这种情况。抱歉,其中有些冗长或不清楚。仍然希望有人能够充分理解它以提供一些建议。当然,将不胜感激。就个人而言,我在选项1和3之间划分,稍微偏向选项3。

0 个答案:

没有答案