Проблема с RESTApi с несколькими вызовами клиентов - PullRequest
0 голосов
/ 18 мая 2019

Я новичок в отдыхе и пытаюсь написать простой API отдыха, который переносит некоторую сумму из одного источника в другой.У меня нет базы данных, использую карту в качестве источника данных.Мой сервис просто проверяет, достаточно ли источника для перевода, если это так, то я обновляю и источник, и цель.Проблема в том, что я беспокоюсь о нескольких запросах одновременно.Поскольку при наличии нескольких запросов они могут одновременно выполнять проверку с одинаковыми исходными значениями, что приводит к неправильному поведению.

Пример: источник имеет сумму 100, и существует 2 запроса на передачу на сумму 70Обрабатывая оба запроса, они одновременно проверяют, что источник имеет сумму 100, после чего они могут выполнить передачу.

1) Мой ресурс:

 public class MyResource {

    @Inject
    TransferService transferService;


    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public Transfer transfer(Transfer transfer){

        return transferService.transfer(transfer);
    }
}

2) Источник POJO

public class Source {

    private String sourceId;
    private double balance;

    ....

}

3) Служба источника

public class SourceServiceImp implements SourceService {


    @Override
    public Source getSource(String sourceId) {

        Source source = EmbeddedSources.getSource(sourceId);

        return source;

    }


    public boolean deposit(String sourceId, double amount ){

        Source source = getSource(sourceId);
        source.setBalance(source.getBalance() + amount);

        EmbeddedSources.updateSource(sourceId, source);
        return  true;
    }


    public boolean withdraw(String sourceId, double amount ){

        Source source = getSource(sourceId);
        source.setBalance(source.getBalance() - amount);

        EmbeddedSources.updateSource(sourceId, source);
        return  true;
    }


}

4) TransferService

public class TransferServiceImpl implements TransferService {


    private static SourceService sourceService ;


    public TransferServiceImpl(SourceService sourceService){
        this.sourceService = sourceService;
    }


    @Override
    public Transfer transfer(Transfer transfer) {

        Source sourceSource = sourceService.getSource(transfer.getSourceSourceId());
        Source destSource = sourceService.getSource(transfer.getDestSourceId());
        double amount = transfer.getAmount();



        if(isBalanceEnough(sourceSource, destSource, amount)){
            sourceService.withdraw(sourceSource.getSourceId(), amount);
            sourceService.deposit(destSource.getSourceId(), amount);     
        }

        transfer.setStatus("VALID");
        return transfer;

    }

}

5) Встроенная БД

public class EmbeddedSources {

    private static Map<String, Source> sourceMap = new ConcurrentHashMap<>();
    private static Map<String, Transfer> transferMap = new ConcurrentHashMap<>();


    public static Source getSource(String sourceId){
        return sourceMap.get(sourceId);
    }

    public static void updateSource(String sourceId, Source source){
        sourceMap.put(sourceId, source);
    }


    public static void addSource(Source source){
        sourceMap.put(source.getSourceId(), source.deepCopy());
    }

}

Я думал об использовании очереди для запроса, но считаю, что это не хорошее решение.Также я подумал об использовании volatile для полей класса источника, но все же это не предотвратит проблему многократного запроса для одного и того же sourceId.

Как я могу предотвратить эту проблему и сделать сервис безопасным для нескольких запросов?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...