【问题标题】:How to ensure that there are no race conditions in a database update statement using spring如何使用spring确保数据库更新语句中没有竞争条件
【发布时间】:2019-04-17 12:06:38
【问题描述】:

假设有两个实体ChildrenGifts。假设有 1000 个孩子和 10 份礼物。孩子们总是会尝试抢夺可用的礼物,礼物将按照“先到先得”的原则贴上标签。

表结构

children

+----+------+
| id | name |
+----+------+
|  1 | Sam  |
|  2 | John |
|  3 | Sara |
+----+------+

gift

+----+---------+-------------+
| id |  gift   | children_id |
+----+---------+-------------+
|  1 | Toy Car |           2 |
|  2 | Doll    |           3 |
+----+---------+-------------+

这里的children_id 是第一个抢到礼物的孩子。

在我的应用程序中,我想更新children_id,这样只有发起请求的第一个孩子会得到它,其余的孩子会得到GiftUnavailableException

我将如何确保即使一次有 1000 个请求来获取特定的礼物,也只有第一个会得到它。或者我将如何确保此更新不存在竞争条件。

是否有任何我可以使用的弹簧特定功能或有其他方法。

我使用 spring-boot 作为我的后端。

【问题讨论】:

  • 如果您在一台机器上有多个线程,请使用synchronized
  • 1.确保在事务中执行。 2. 首先对Gift 进行排他锁 - 比如@Lock(LockModeType.PESSIMISTIC_READ) Gift findOne(Long id)。 3. 一旦Gift 被检索到,立即检查它是否未被认领。如果是,则退出(抛出异常、返回错误等)。 4. 如果礼物没有被认领,将认领人分配给它,并保存。这样,可以并行处理多个索赔,只要是针对不同的礼物,同时针对相同礼物的并发索赔将被拒绝,即使它们在不同的机器上运行。

标签: java database spring spring-boot concurrency


【解决方案1】:

我不能发表评论,所以我去!

我假设您使用的是 Spring Data JPA。

那么你应该使用@Transactional注解:这意味着每次你请求你的数据库时,你都会做一个事务:

  1. 开始交易
  2. 执行交易
  3. 提交事务

很多有用的信息(阅读!!):Spring @Transactional - isolation, propagation

您需要将事务隔离设置为可序列化,并可能更改传播方法。

如果你没有使用 Spring data JPA.. 那么有一个同步的关键字,但我认为在这里使用它有点糟糕。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-18
    相关资源
    最近更新 更多