如何解决Spring Boot项目中REST服务的并发问题?

问题描述 投票:0回答:1

我有一个 Spring Boot 项目。

想象两个 API 接受相同的对象作为输入,并用它来做不同的事情。 在执行操作之前,每个API都会验证对象,特别是有一个名为progressiveNr的数字字段,这个数字基本上用于了解特定凭证的请求进度(不详细说明,如果不清楚我会讨论它) ).

每个API都会根据优惠券检查progressiveNr是否正确,因此您不能向我发送progressiveNrs 1、2、4、3,但必须按顺序发送。

事情就是这样,客户端调用了 2 个 API,间隔几毫秒: API 1 {requestId:196,voucherId:1,progressiveNr:2},API 2 {requestId:197,voucherId:1,progressiveNr:3}。

对于 requestId 197,我们给出了错误“progressiveNr 必须为 2”。 这是因为,正是在 196 正在处理时,它仍处于验证阶段,因此尚未执行任何插入,另一个 API 是通过 197 调用的,其值为 3,然而,考虑到 196 尚未在在插入阶段,表格仍然正确地显示progressiveNr=1,因此给出了一个错误,说我期望progressiveNr=2。

在互联网上搜索我发现锁作为解决方案,但我不清楚如何应用它..

这些是控制器调用的方法

    @Override
    @LogExecutionTime(printArgs = true, printResponse = true)
    public ResponseDTO subve(List<RequestSubveDTO> richieste) {
        List<ScartoTracciatoConnexa> daScartare = new ArrayList<>();

        //requests subve validation
        richieste.forEach(request -> {
            ScartoTracciatoConnexa sTC = validateSubve(request);

            if (sTC != null) daScartare.add(sTC);
        });

        //do other things

        //do the action
        asyncService.subve(richieste, daScartare);

        return new ResponseDTO(EsitiCodes.REQUEST_ACCEPTED);
    }

    private ScartoTracciatoConnexa validateSubve(RequestSubveDTO request) {
        try {
            validatorService.validateSubve(request);
        } catch (InvalidRequestException e) {
            return generaScarto(request, request.getNumVoucher(), SUBVE, e);
        }

        return null;
    }

    @Override
    @LogExecutionTime(printArgs = true, printResponse = true)
    public ResponseDTO renew(List<RequestRenewDTO> richieste) {
        List<ScartoTracciatoConnexa> daScartare = new ArrayList<>();

        //requests renew validation
        richieste.forEach(request -> {
            ScartoTracciatoConnexa sTC = validateRenew(request);

            if (sTC != null) daScartare.add(sTC);
        });

        //do other things

        //do the action
        asyncService.renew(richieste, daScartare);

        return new ResponseDTO(EsitiCodes.REQUEST_ACCEPTED);
    }

    private ScartoTracciatoConnexa validateRenew(RequestRenewDTO request) {
        try {
            validatorService.validateRenew(request);
        } catch (InvalidRequestException e) {
            return generaScarto(request, request.getNumVoucher(), RENEW, e);
        }

        return null;
    }

这是我的验证器服务:

    @LogExecutionTime
    @Transactional(readOnly = true)
    public void validateRenew(RequestRenewDTO dto) throws InvalidRequestException {
        //Other validations

        //progressiveNr validation
        int lastProgNr = myObjectService.getLastProgNumByVoucherId(dto.getVoucherId()) + 1;

        if (lastProgNr != dto.getProgressiveNr())
            throw new InvalidRequestException();
    }

    //THE SAME FOR validateSubve(RequestSubveDTO dto)

有人可以帮助我吗?预先感谢!

java spring-boot concurrency
1个回答
0
投票

锁和“阻塞”仅在两个服务“实际上”同时处理并持有锁时才相关。但是,如果对服务 3 的请求比服务 2 早一整秒(或 10!)到达,该怎么办?当服务 2 尚未运行时,它无法持有锁(以阻止服务 3).. “等待”更重要,所以这里相关的是什么..但是您需要问自己,服务 3 应该等待多长时间才能查看服务 2 是否完成?

如果您想让服务等待其前一个服务,那么每个服务都需要执行重新检查,以查看前一个服务是否已完成或在超时时失败。

或者,

可能是更好的解决方案

,您可以在 API 中指定,在响应确认服务 2 已成功完成之前,不得发送对服务 3 的请求。

© www.soinside.com 2019 - 2024. All rights reserved.