我的应用程序是基于表单的应用程序,用户可以在其中提出请求,将为该请求分配一个ID,用户将填写一些详细信息,然后通过不同的阶段提交。多个用户可能成为一个请求的一部分的问题,因此可能存在用户A和用户B同时查看表单的情况。用户A可能先提交,然后用户B提交,这将导致请求仅显示用户B提交的信息。为解决此问题,我提出了两种解决方案:
-在将数据提交到数据库之前,我们先进行一次get调用,以查看数据是否已经提交(我们在应用程序中使用状态。因此,我们将检查“阶段#待处理”的状态)。 / p>
-我们为其他一些服务实现了Redis缓存。我可以添加类似的内容
public submitRequest() {
RMap<String, int> requestLockMap = redissonClient.getMap("requestLock");
if(requestLockMap.get('request_ID') == 0) {
requestLockMap.put('request_ID', 1);
...continue submitting request...
}
}
这实际上是在Redis缓存中增加了竞争条件。但是,我不知道这两种方法是否是一种好的做法。有更好的选择吗?我将Spring用作我们的Java框架,因此,如果对此有任何解决方案,我很乐意听到。
答案 0 :(得分:1)
为每个提交分配随机生成的ID有什么弊端?
例如使用UUID
UUID.randomUUID().toString()
您可以将相同请求ID的机会统计上降低为0。DBcolissions可被视为例外,因为这种情况不太可能发生。
使用这种方法,还可以避免未经授权的用户可以使用先前的请求ID查看/编辑相邻信息的情况。
答案 1 :(得分:1)
不要遵循第二种解决方案。正如您所说,很可能会导致比赛状况。
您的第一个建议是正确的。关键是要在事务内进行更新,并在那里检查状态是否符合预期,因此您可以继续进行更新。
状态类似于具有版本ID。更新条目时,版本ID会增加。因此,后续/并行编辑将具有无效的版本号或状态,因此无法继续进行。如果您的状态不是未决,则不会进行更新。
在事务内部,您可以回滚并向用户返回错误消息,即请求已由用户X编辑。
但是,如果有许多状态,则最好使用版本ID代替状态。
另一种方法是在更新语句的where子句中添加所需的状态,如here所示,以避免更新修改后的行。
Hibernate具有实现optimistic locking的内置机制。有关详细信息,请参见this。
答案 2 :(得分:1)
我建议在表中有一个时间戳字段,供用户更新。当您向用户显示表单时,请阅读时间戳并将其保持在会话中。更新时,请执行类似update table A set some_column = 'value', timestamp = now() where id = 1 and timestamp = 'whatever timestamp you read earlier'
的操作。然后查看update语句的返回值(如果为1),则更新了该行,如果为0,则另一用户已更新-向该用户显示一些错误/通知。当然,您需要在每次更新期间更新时间戳字段。
答案 3 :(得分:0)
一种解决方案是使用自动递增整数字段。当您获取将具有一个值的记录并将其包含在表单信息中时。提交表单后,将读取记录以查看其基石是否具有相同的值。如果是这样,请提交。如果不是,请拒绝并向用户发送错误消息,告知他们为时已晚。
由于该字段在每次提交时都会自动递增,因此您无需执行其他任何操作即可确保提交的表单为此字段包含相同的值。