Cześć,
uczę się springa i w tym celu stworzyłem aplikację Restową do zarządzania ogłoszeniami.
Ostatnio znalazłem błąd polegający na tym, że jak ktoś na froncie uzupełni formularz i chce zapisać ogłoszenie ale kliknie przycisk zapisz dwukrotnie to wysyłają się do back-endu dwa requesty i finalnie w bazie mam zapisane 2 takie same ogłoszenia.
Zanim zablokuje możliwość ponownego kliknięcia na froncie chciałby wprowadzić zabezpieczenie przed taką sytuacją po stronie back-endu.
Mam testy integracyjne kontrolera w którym dodałem kolejny test symulujący taką sytuację.
@DatabaseSetup(value = "/datasets/main/adverb.xml", connection = DBUNIT_CONNECTION)
public void test() throws Exception {
......
Thread thread = new Thread(() -> {
try {
MvcResult result = this.mocMvc.perform(
post("/adverb/add")
.header("Content-Type", "application/json")
.content(request)
)
.andDo(print())
.andExpect(status().isOk())
.andReturn();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
Thread thread2 = new Thread(() -> {
try {
MvcResult result2 = this.mocMvc.perform(
post("/adverb/add")
.header("Content-Type", "application/json")
.content(request)
)
.andDo(print())
.andExpect(status().isOk())
.andReturn();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
thread.start();
thread2.start();
thread.join();
thread2.join();
List<AdverbEntity> adverbs = adverbRepository.findAll();
}
w serwisie natomiast mam taką metodę.
public void save(AdverbEntity adverbEntity){
LOGGER.info("start" );
List<AdverbEntity> check = adverbRepository.checkIfExist(...);
if(check.size() == 0){
adverbRepository.saveAll(adverbEntity);
}
LOGGER.info("stop");
}
Myślałem, że dodanie adnotacji @Transactional nad metodą save spowoduję, że tylko jeden wątek będzie miał dostęp do metody.
Tymczasem po logach widzę, że oba wątki w tym samym czasie są w metodzie i finalnie zapisują się dwa ogłoszenia.
Dodam, że wczesniej nie miałem doczynienia ani z wątkami ani tranzakcjami w springu więc jeśli źle myśle i problemu nie da się rozwiązać używając w ten sposób @Transactional wyprowadźcie mnie z błędu.