Używam Spring Boot (1.4.4.REALEASE) z danymi sprężystymi w celu zarządzania bazą danych MySql. Mam następujący przypadek:Rodzime zapytanie źródłowe wykonywane w ramach transakcji o nieaktualnej wartości
- Aktualizujemy jedną rewizję wykonaną w jednym urządzeniu przy użyciu
RevisionService
. RevisionService
zapisuje wersję i wywołujeEquipmentService
, aby zaktualizować stan urządzenia.- Obiekt updateEquipmentStatus wywołuje procedurę składowaną Db w celu oceny sprzętu wraz z jego wersjami i aktualizacji pola.
Próbowałem niektórych opcji, ale nie udało się uzyskać zaktualizowanego statusu sprzętu. Metoda updateEquipmentStatus
zapisuje poprzedni status urządzenia (nie biorąc pod uwagę aktualnej wersji zapisanej w transakcji). Kod jest napisany w ten sposób:
RevisionService
@Service
public class RevisionService{
@org.springframework.transaction.annotation.Transactional
public Long saveRevision(Revision rev){
//save the revision using JPA-Hibernate
repo.save(rev);
equipmentService.updateEquipmentStatus(idEquipment);
}
}
EquipmentService
@Service
public class EquipmentService{
@org.springframework.transaction.annotation.Transactional
public Long updateEquipmentStatus(Long idEquipment){
repo.updateEquipmentStatus(idEquipment);
}
}
EquipmentRepo
@Repository
public interface EquipmentRepo extends CrudRepository<Equipment, Long> {
@Modifying
@Procedure(name = "pupdate_equipment_status")
void updateEquipmentStatus(@Param("id_param") Long idEquipment);
}
O ile rozumiem, ponieważ obie metody są opatrzone adnotacją w transakcjach Springa, metoda updateEquipmentStatus
powinna zostać wykonana w zakresie bieżącej transakcji. Próbowałem również z różnymi opcjami dla opisu @Transactional
z updateEquipmentStatus
, takimi jak @Transactional(isolation=Isolation.READ_UNCOMMITTED)
(które nie powinny być wymagane, ponieważ używam tej samej transakcji) i @Transactional(propagation=Propagation.REQUIRES_NEW)
, ale nadal nie biorę pod uwagę obecnego stanu. To jak mój procedura przechowywana jest zapisany w MySQL DB:
CREATE DEFINER=`root`@`localhost` PROCEDURE `pupdate_equipment_status`(IN `id_param` INT)
LANGUAGE SQL
NOT DETERMINISTIC
MODIFIES SQL DATA
SQL SECURITY DEFINER
COMMENT ''
BEGIN
/*Performs the update considering tequipment and trevision*/
/*to calculate the equipment status, no transaction is managed here*/
END
Chciałbym także zaznaczyć, że jeśli wykonam jakąś modyfikację samego sprzętu (co wpływa tylko Tequipment), status jest odpowiednio aktualizowany. InnoDb jest silnikiem stosowanym do wszystkich tabel.
UPDATE
Wystarczy zmieniła sposób repo użyć nativeQuery zamiast i ten sam problem będzie się powtarzał, więc procedura Db angażowania należy wyrzucić:
@Modifying
@Query(nativeQuery = true, value= "update tequipment set equipment_status = (CASE WHEN (...))")
void updateEquipmentStatus(@Param("id_param") Long idEquipment);
UPDATE2
Uczyniwszy więcej testów i dodaje dziennik z TransactionSynchronizationManager.getCurrentTransactionName()
w sposobach, to konkretny problem:
- Zmiany przeprowadzone w służbie urządzenia są prawidłowo zbierane przez funkcję aktualizacji (gdy coś się zmienia Tequipment status w tequipment jest obliczany prawidłowo).
- Zmiany dokonane w usłudze rewizji (trevisie) powodują nieaktualną wartość w tequipment (nie ma znaczenia, czy Spring robi to w innej transakcji za pomocą REQUIRES_NEW, czy nie). Spring wydaje się poprawnie utworzyć nową transakcję przy użyciu REQUIRES_NEW w
establishEquipmentStatus
, ponieważ bieżąca nazwa transakcji zmienia się, ale zapytanie natywne nie ma ostatnich wartości (z powodu transakcji przed nieprzeprowadzeniem zobowiązania?). Próbowano także usunąć@Transactional
zestablishEquipmentStatus
, aby ta sama transakcja była używana, ale problem nadal występuje. - Chciałbym, aby podświetlić, że zapytanie używane do aktualizacji statusu sprzętu ma case expression z wieloma podzapytaniami przy użyciu trevision.
Cześć, przepraszam za Opóźnienie. W rzeczywistości problem nie jest związany z procedurą przechowywaną, ale wydaje się, że ma więcej wspólnego z wieloma tabelami związanymi z tą samą transakcją (pobiera stare wartości z tabeli). Mniej więcej to przepływ wykonania: 1. Zaktualizuj wersję za pomocą Hibernate. 2. Wykonaj metodę "updateEquipmentStatus", która uruchamia modyfikujące natywne zapytanie (w zapytaniu tym wykorzystuje się dane związane z krokiem 1, który jest nieaktualny). –