Spring @Transactional + Isolation.REPEATABLE_READ用于速率限制

时间:2018-01-13 10:47:14

标签: spring multithreading transactional transaction-isolation

我们正在尝试限制总数的情况。一个月内请求的JSON记录为10000的API。 我们将针对client_id和时间戳(主键)存储在表中的记录总数。 根据请求,我们从该表中获取该客户端的记录,其中包含该月份的Timestamp。 从这条记录中我们得到当前的计数,然后用no增加它。请求中的当前记录,并更新数据库。

使用Spring Transaction,伪代码如下

@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.REPEATABLE_READ)
public void updateLimitData(String clientId, currentRecordCount) {

//step 1
    startOfMonthTimestamp = getStartOfMonth();
    endOfMonthTimestamp = getEndOfMonth();

//step 2
    //read from DB
    latestLimitDetails = fetchFromDB(startOfMonthTimestamp, endOfMonthTimestamp, clientId);
    latestLimitDetails.count + currentRecordCount;

//step 3
    saveToDB(latestLimitDetails)

} 

我们希望确保在多个线程访问" updateLimitData()"方法,每个线程获取clientId的更新数据一个月,并且它不会错误地覆盖计数。 在上面的场景中,如果多个线程访问方法" updateLimitData()"并到达"步骤3"。第一个帖子将更新" count"在DB中,然后第二个线程更新" count"在DB中可能没有最新的计数。

我从Isolation.REPEATABLE_READ了解到"写锁定"在&#34时调用更新时放置在行中;步骤3"只有(到那时其他线程将有陈旧数据)。我怎样才能确保线程总是在多线程场景中从表中获得最新计数 我想到的一个解决方案就是同步这个块,但这在多服务器场景中效果不佳。

请提供解决方案。

1 个答案:

答案 0 :(得分:0)

除非您在执行此操作时锁定表/行,否则事务不会对您有所帮助(不要这样做会影响性能)。

您可以将其迁移到数据库,使用存储过程或函数调用在数据库中执行此增量。这将确保ACID和事务安全性,因为它内置于数据库中。

我建议使用标准的Spring Actuator来生成API调用计数,但这意味着重写您的服务以使用执行器端点而不是数据库。您可以将其链接到您的Gateway / Firewall / Load-balancer,以在达到其报价后拒绝访问API。这意味着您的API端点是纯粹的,并且从API调用中删除了此逻辑。您开发人员的所有新API都将自动获得此功能。

相关问题