AuditLog zmian dla DB SpringBoot

AuditLog zmian dla DB SpringBoot
T9
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 3 lata
  • Postów:48
0

Cześć,
Potrzebuję dla kilku encji z użyciem spring boot i JPA Repository zrobić mechanizm auditlog. Powinien on zapisywać do tabeli czynność wykonywaną oraz zapisywać to co się zmieniło w danym rekordzie (przy update).
Jednym z rozwiązań jakie przychodzą mi do głowy, to ręczne wywoływanie takiego mechanizmu, tzn przy każdym wywołaniu save, update, delete dla konkretnych repozytoriów, pobierać rekord przed, rekord zmieniony - porównywać i zapisywać dane. Jednak architektura systemu ma wiele do życzenia i przykładowo zapis obiektu użytkownika wywoływany jest w kilku miejscach, przez co prowadziło by to do dodatkowej duplikacji kodu i odszukiwania wszystkich tych miejsc oraz problem w dalszym rozwoju i utrzymaniu, bo ktoś może kiedyś zapomnieć logować dane. Nie wiem czy to rozwiązanie jest poprawne, eleganckie i na "topie" - na pewno zadziała.
Próbuję poszukać innych, lepszych rozwiązań. Widziałem, że sam spring ma mechanizm logowania danych, ale stosowany(przynajmniej w przykładach) był tylko do zapisu daty utworzenia, daty ostatniej zmiany a ja potrzebuję też zapisywać to co się zmieniło i nie mam pewności co do użycia go... Ktoś ma jakiś pomysł?

Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Mimo wszystko sugeruje zrefaktorować ten kod, tak żeby mieć jedno ładne repozytorium a nie X miejsc które na janusza uderzają do bazy.
JPA/Hibernate ma takie coś jak Envers.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
T9
Repozytorium dziedziczące po JpaRepository dla każdej encji jest jedno, tylko wywołania tego repozytorium już są w różnych serwisach.
Shalom
JpaRepository to nie jest repozytorium tylko taka niskopoziomowa CRUDowa nakładka na bazę. Ja mówię o repozytorium w sensie operacji biznesowych.
dymul
  • Rejestracja:około 11 lat
  • Ostatnio:ponad rok
  • Postów:182
0

Jedno eleganckie rozwiązanie już padło - jest ono prawdopodobnie najlepsze ale zależnie od poziomu burdelu w projekcie jednocześnie najbardziej pracochłonne.
Z mniej pracochłonnych rozwiązań - można to aspektowo opędzlować, wtedy można jakiś kawałek kodu wykonać za każdym razem jak jakaś metoda z JpaRepository zostanie wywołana - od razu mówię nie rekomenduję tego bo zaraz przybiegnie @jarekr000000 i mnie wyruguje z forum.
Jest jeszcze opcja triggera na bazie, który zapisze te dane do dodatkowej tabeli - możliwe tylko jeżeli dane, które musisz zalogować są w całości dostępne w bazie. Plusem będzie transakcyjność ogarnięta na poziomi bazy i gwarancja wykonania nawet jeżeli ktoś nagle postanowi wrzucić dane do bazy jakimś skryptem.
Przemyśl i przeanalizuj w kontekście Twojego przypadku bo dobrej odpowiedzi nie ma.

T9
To jedno eleganckie i pracochłonne rozwiązanie to użycie tego Envers i dorzucenie hibernate czy wydzielenie głównego repozytorium i w nim obsługa zapisu danych audytowych z odwołaniem do JPA Repository? Takie repozytorium powinno być per encja/Jpa Repository czy jedno zbiorcze?
T9
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 3 lata
  • Postów:48
0
Shalom napisał(a):

Mimo wszystko sugeruje zrefaktorować ten kod, tak żeby mieć jedno ładne repozytorium a nie X miejsc które na janusza uderzają do bazy.
JPA/Hibernate ma takie coś jak Envers.

Dobrze rozumiem, że ten Envers jest tylko w hibernate? Używając "czystego" spring-date JPA nie ma Envers? Co w takim przypadku poleciłbyś?
Dodatkowo potrzrebuję zapisywać zmiany z LdapRepository, o czym wcześniej nie wspomniałem, czy Envers obsłuży, jeśli nie ma kopii danych z ldapa w lokalnej bazie?

edytowany 1x, ostatnio: turo90
Charles_Ray
nie ma czegoś takiego jak "czysty" JPA, pod spodem masz na 90% Hibernate
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Postów:1875
0

”Engineering is easy. People are hard.” Bill Coughran
edytowany 2x, ostatnio: Charles_Ray
nie100sowny
  • Rejestracja:około 9 lat
  • Ostatnio:około 10 godzin
  • Lokalizacja:Kraków
  • Postów:402
0
turo90 napisał(a):

Cześć,
Potrzebuję dla kilku encji z użyciem spring boot i JPA Repository zrobić mechanizm auditlog.
[...]
i przykładowo zapis obiektu użytkownika wywoływany jest w kilku miejscach, przez co prowadziło by to do dodatkowej duplikacji kodu i odszukiwania wszystkich tych miejsc oraz problem w dalszym rozwoju i utrzymaniu, bo ktoś może kiedyś zapomnieć logować dane.

Masz repozytorium, które implementuje JpaRepository. Normalnym sposobem byłoby zaimplementować drugie repozytorium - dekorator. To drugie repozytorium zwyczajnie logowało by operację i wywoływało to pierwsze repo. Następnie wystarczy zamiast new UserRepository() utworzyć new LoggingRepository(new UserRepository()). Podobnie zrobić z repozytorium LDAP. Taka zmiana jest transparentna dla kodu, który używa tych repozytoriów.

Niestety używasz Springa do tworzenia tych repozytoriów i żeby zrobić taką dekorację potrzebujesz potworka o nazwie @NoRepositoryBean
https://dzone.com/articles/customizing-spring-data-jpa

Ewentualnie tworzyć te repozytoria nie magią adnotacji, a poprosić Springa o jego różdżkę. Wówczas możesz je stworzyć jako @Bean i udekorować swoim logowaniem:
https://docs.spring.io/spring-data/data-commons/docs/current/reference/html/#repositories.create-instances.standalone

Kopiuj
RepositoryFactorySupport factory =// Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class);

"Gdy się nie wie, co się robi, to się dzieją takie rzeczy, że się nie wie, co się dzieje"
edytowany 5x, ostatnio: nie100sowny
Charles_Ray
W jaki sposób wtedy zalogujesz dokładnego diffa przy update?
nie100sowny
Diff to osobny problem. Najłatwiej po prostu zapisywać gdzieś każdą wersję obiektu. Jeżeli faktycznie potrzebujemy diff to trzeba by wczytać obecny obiekt i sprawdzić zmiany.
Charles_Ray
I tu jest pies pogrzebany IMO. Od tego kejsu bym zaczął.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.