Проблема многопоточности при попытке выбрать и вставить в один метод - PullRequest
0 голосов
/ 25 января 2019

Друзья! Я работаю с Play + Java + Ebean. У меня проблема с параллельными потоками при попытке выбрать и вставить значения в БД одним способом. Сначала я проверяю наличие устройства в моей БД (PostgreSQL) по id. Если я не нашел устройство по идентификатору, я пытаюсь вставить его в БД. Затем я возвращаю объект устройства. Все работает отлично, за исключением ситуации, когда два http-запроса асинхронно пытаются отправить мне одинаковые идентификаторы устройства. Во-первых, оба они выбирают значение из БД и ничего не возвращают. Затем один вводит значения, а второй завершается неудачей из-за io.eBean.DuplicateKeyException.

Я пытался синхронизировать метод. Это работает, но мне не нравится это решение. Если я сделаю это, многие запросы будут помещены в очередь. Я хочу оставаться в параллели, но синхронизироваться, только если у меня есть два или более запросов с одинаковым идентификатором. Другой способ решить эту проблему - написать запрос с помощью INSERT ... WHERE NOT EXISTS (SELECT ...) RETURNING. Но это не объектный стиль, и существует жесткое кодирование для нескольких операций одного типа.

public CompletionStage<Device> getDevice(String deviceID, String ipAddress) {
return CompletableFuture.supplyAsync(() -> 
SecurityRepository.findDeviceByDeviceID(deviceID))       
    .thenApplyAsync(curDevice -> curDevice
        .orElseGet(() -> {
            List<Device> devices = 
            SecurityRepository.listDevicesByIpAddress(ipAddress);
            if(devices.size() >= 10) {
                 for(Device device : devices)
        device.delete();
    }
    Device newDevice = new Device();
    newDevice.setDeviceID(deviceID);
    newDevice.ipAddress = ipAddress;
    newDevice.save(); //here is the problem
    return newDevice;
      })
);

}

Я хочу синхронизировать этот метод, если и только если deviceID одинаков. У вас есть предложения по этой проблеме? Спасибо.

...