Я бы предложил вам синхронизировать доступ к БД. Поэтому операции select
, save
и update
должны выполняться в синхронизированном блоке. Но это сократит параллелизм до одного потока, и снижение производительности будет огромным. Таким образом, есть некоторая хитрость, которую вы можете использовать для синхронизации доступа к БД, но с некоторой скоростью сохранить производительность.
Вы можете синхронизировать доступ к БД по хешу мормизованного URL. Я использую url_hash %10000
, чтобы ограничить количество объектов блокировки. Конечно, это повлияет на производительность, но будет на 10000 лучше, чем простая синхронизация.
Посмотрите на код:
private final static String UUID_PATTERN = "[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}";
private final static String SIM_NUMBER_PATTERN = "[0-9]{19}";
private final static String MSISDN_SHORT_PATTERN = "[0-9]{9}";
private final static String MSISDN_LONG_PATTERN = "[0-9]{11}";
private final Map<Integer, Object> locks = new ConcurrentHashMap<>();
@Transactional
public ResponseEntity<Status> processScanWebAppRequest(ServiceDiscovery serviceDiscovery){
try {
String urlToLookFor = normalizeUrl(serviceDiscovery.getUrl());
int lockHash = urlToLookFor.hashCode() % 10000;
synchronized (locks.computeIfAbsent(lockHash, integer -> new Object())) {
Optional<WebApp> wa = checkRegexes(urlToLookFor);
if (wa.isPresent()){
updateExistingWebApplication(serviceDiscovery, wa.get());
} else {
saveNewWebApplication(serviceDiscovery);
}
}
} catch (IncorrectResultSizeDataAccessException ex) {
return new ResponseEntity<Status>(new Status("Processing error"), HttpStatus.PRECONDITION_FAILED);
}
return new ResponseEntity<Status>(new Status("OK"), HttpStatus.OK);
}
private String normalizeUrl(String url) {
String urlToLookFor = url.replaceAll(UUID_PATTERN,UUID_PATTERN);
urlToLookFor=urlToLookFor.replaceAll(SIM_NUMBER_PATTERN,SIM_NUMBER_PATTERN);
urlToLookFor=urlToLookFor.replaceAll(MSISDN_LONG_PATTERN,MSISDN_LONG_PATTERN);
urlToLookFor=urlToLookFor.replaceAll(MSISDN_SHORT_PATTERN,MSISDN_SHORT_PATTERN);
return urlToLookFor;
}
private Optional<WebApp> checkRegexes(String url) {
return waRepository.getWebAppByRegex(urlToLookFor+"$");
}