假设您有一个系统同时处理请求,最终结果是在数据库中存储字段。现在假设出现以下情况,其中id
请求ID user
是进行调用的用户,val
是存储在数据库中的值,t
是时间:
Client Server Database
| id=1, user=x, val=100, t=1 | |
|----------------------------> | |
| id=2, user=x, val=50, t=2 | |
|----------------------------> | id=2, user=x, val=50, t=3 |
| |---------------------------->|
| | id=1, user=x, val=100, t=4 |
| |---------------------------->|
问题是同一个用户几乎同时发出两个请求,但是由于服务器中任务的无序执行,最后一个请求被处理,这个值被插入到数据库中,而第一个请求来到并覆盖此数据,最终使数据库处于不一致状态。
我想到了两个解决方案:
在数据库中添加creation_time
字段,仅在objectToBeInserted.creationTimestamp > objectAlreadyInDb.creationTimestamp
时更新。但这种用途有限;假设您应该向另一个系统发出请求而不是数据库,因此您无法查询数据库。
与Map
相关联的userId
用户semaphore
。当请求到达时,检查是否采用了与该用户对应的信号量;如果被采取然后等待继续。插入数据库后,释放信号量。然而,这具有无法同时处理来自同一用户的请求的限制,并且如果有许多用户但是在快乐情况下更快(仅一个数据库调用),则可能存在内存问题。
这些解决方案是否足够好,或者是否有更好的解决此问题的典型解决方案?
答案 0 :(得分:1)
最典型的解决方案是添加序列号。或者您可以使用MQ软件来保证有序处理(这些通常在内部使用序列号来保证排序)。使用MQ可能是一个好主意,因为如果丢失消息(如果丢失消息#2,#3,#4不会被处理等),MQ很容易停止处理,以及MQ有防止消息丢失的机制。
编辑:此article中有一个很好的讨论,解释了不同的设计。对于您的问题,第三个端点必须提供事务,但只要它不是,它就不必是数据库。