Logika biznesowa w bazie danych za pomocą SchemaKeeper

Celem tego artykułu jest pokazanie narzędzi, które mogą znacznie uprościć proces rozwijania baz danych w ramach projektów PHP, wykorzystujących systemy zarządzania bazami danych PostgreSQL, na przykładzie biblioteki schema-keeper . Informacje zawarte w tym artykule będą przede wszystkim przydatne dla deweloperów, którzy chcą maksymalnie wykorzystać możliwości PostgreSQL, ale napotykają problemy z utrzymywaniem logiki biznesowej przeniesionej do bazy danych.

Artykuł nie będzie opisywał zalet ani wad przechowywania logiki biznesowej w bazie danych. Zakłada się, że wybór został już dokonany przez czytelnika.

Zostaną omówione następujące kwestie:

W jakiej formie przechowywać zrzut struktury bazy danych w systemie kontroli wersji (dalej w tekście — VCS)

  1. Jak śledzić zmiany w strukturze bazy danych po zapisaniu zrzutu
  2. Jak przenosić zmiany w strukturze bazy danych na inne środowiska bez konfliktów i gigantycznych plików migracji
  3. Jak zorganizować proces równoległej pracy nad projektem kilku deweloperów
  4. Jak bezpiecznie wprowadzać większą ilość zmian w strukturze bazy danych na środowisko produkcyjne
  5. SchemaKeeper

    jest zaprojektowany do pracy z procedurami składowanymi napisanymi w języku PL/pgSQL . Testowanie z innymi językami nie było przeprowadzane, dlatego użycie może być mniej efektywne lub niemożliwe.W jakiej formie przechowywać zrzut struktury bazy danych w VCS

oferuje funkcję

Biblioteka schema-keeper saveDump , która zapisuje strukturę wszystkich obiektów z bazy danych w postaci osobnych plików tekstowych. Na wyjściu tworzony jest katalog zawierający strukturę bazy danych, podzieloną na pogrupowane pliki, które łatwo dodać do VCS.Rozważmy konwersję obiektów z bazy danych na pliki na kilku przykładach:

Typ obiektu

Ścieżka względna do pliku
Schemat
Nazwa
Tabela

accounts
public
./public/tables/accounts.txt
Procedura składowana

auth(hash bigint)
public
./public/functions/auth(int8).sql
booking

Reprezentacja
tariffs
./booking/views/tariffs.txt
Zawartość plików to tekstowa reprezentacja struktury konkretnego obiektu bazy danych. Na przykład, dla procedur składowanych zawartość pliku będzie pełną definicją procedury składowanej, zaczynającą się od bloku

CREATE OR REPLACE FUNCTION Jak widać z powyższej tabeli, ścieżka do pliku zawiera informacje o typie, schemacie i nazwie obiektu. Takie podejście ułatwia nawigację po zrzucie oraz przegląd zmian w bazie danych..

.sql

Rozszerzenie .sql dla plików z kodem źródłowym procedur przechowywanych, wybrano, aby IDE automatycznie dostarczały narzędzia do interakcji z bazą danych przy otwieraniu pliku.

Jak przenosić zmiany w strukturze bazy danych na inne środowiska bez konfliktów i gigantycznych plików migracji

Zapisując zrzut bieżącej struktury bazy danych w VCS, uzyskujemy możliwość sprawdzenia, czy wprowadzano zmiany w strukturze bazy po utworzeniu zrzutu. W bibliotece schema-keeper w celu wykrycia zmian struktury bazy danych przewidziana jest funkcja verifyDump, która bez efektów ubocznych zwraca informacje o różnicach.

Alternatywny sposób sprawdzenia polega na ponownym wywołaniu funkcji , która zapisuje strukturę wszystkich obiektów z bazy danych w postaci osobnych plików tekstowych. Na wyjściu tworzony jest katalog zawierający strukturę bazy danych, podzieloną na pogrupowane pliki, które łatwo dodać do VCS., wskazując tę samą katalog, i sprawdzeniu w VCS obecności zmian. Ponieważ wszystkie obiekty z bazy danych są zapisane w osobnych plikach, VCS pokaże tylko zmienione obiekty.
Główną wadą tego sposobu jest konieczność nadpisania plików, aby zobaczyć zmiany.

Jak zorganizować proces równoległej pracy nad projektem kilku deweloperów

Dzięki funkcji deployDump kod źródłowy procedur przechowywanych można edytować w taki sam sposób jak zwykły kod aplikacji. Można dodawać/usuwać nowe linie w kodzie procedur przechowywanych i natychmiast przesyłać zmiany do systemu kontroli wersji lub tworzyć/usuwać procedury przechowywane, tworząc/usuwając odpowiednie pliki w katalogu ze zrzutem.

Na przykład, aby utworzyć nową procedurę przechowywaną w schemacie public , wystarczy stworzyć nowy plik z rozszerzeniem .sql w katalogu public/functions, umieścić w nim kod źródłowy procedury przechowywanej, w tym blok Jak widać z powyższej tabeli, ścieżka do pliku zawiera informacje o typie, schemacie i nazwie obiektu. Takie podejście ułatwia nawigację po zrzucie oraz przegląd zmian w bazie danych., a następnie wywołać funkcję deployDump. Podobnie odbywa się modyfikacja i usuwanie procedur przechowywanych. W ten sposób kod trafia jednocześnie do VCS i do bazy danych.

Jeśli w kodzie źródłowym jakiejkolwiek procedury przechowywanej wystąpi błąd, lub niezgodność między nazwą pliku a procedurą przechowywaną, to deployDump nie zostanie wykonana, wyświetlając komunikat o błędzie. Niespójność procedur przechowywanych między zrzutem a bieżącą bazą danych jest niemożliwa przy użyciu deployDump.

Podczas tworzenia nowej procedury przechowywanej nie ma potrzeby ręcznego wprowadzania poprawnej nazwy pliku. Wystarczy, że plik ma rozszerzenie .sql. Po wywołaniu deployDump tekst błędu będzie zawierał poprawną nazwę, którą można wykorzystać do zmiany nazwy pliku.

deployDump pozwala zmieniać parametry funkcji lub typ zwracany bez dodatkowych działań, podczas gdy w klasycznym podejściu należałoby
najpierw wykonać DROP FUNCTION, a dopiero potem Jak widać z powyższej tabeli, ścieżka do pliku zawiera informacje o typie, schemacie i nazwie obiektu. Takie podejście ułatwia nawigację po zrzucie oraz przegląd zmian w bazie danych..

Niestety, istnieją sytuacje, w których deployDump nie można automatycznie zastosować zmian. Na przykład, jeśli usunięta zostanie funkcja wyzwalająca, która jest używana przez przynajmniej jeden wyzwalacz. Takie sytuacje wymagają ręcznego rozwiązania za pomocą plików migracji.

Jeśli za przenoszenie zmian w procedurach składowych odpowiada schema-keeper, to do przeniesienia pozostałych zmian w strukturze konieczne jest wykorzystanie plików migracji. Na przykład, dobrą biblioteką do pracy z migracjami jest doctrine/migrations.

Migracje powinny być stosowane przed uruchomieniem deployDump. Umożliwia to wprowadzenie wszystkich zmian w strukturze i rozwiązanie problematycznych sytuacji, aby zmiany w procedurach składowych później przeszły bez problemów.

Szczegółowe informacje na temat pracy z migracjami będą opisane w kolejnych rozdziałach.

Jak bezpiecznie wprowadzać większą ilość zmian w strukturze bazy danych na środowisko produkcyjne

Należy utworzyć skrypt pełnej inicjalizacji bazy danych, który będzie uruchamiany przez programistę na jego lokalnej maszynie, dostosowując strukturę lokalnej bazy danych do zapisanej w VCS zrzutu. Najłatwiej jest podzielić inicjalizację lokalnej bazy danych na 3 kroki:

  1. Import pliku z podstawową strukturą, który będzie nazywał się na przykład base.sql
  2. Zastosowanie migracji
  3. Wywołanie deployDump

base.sql — to punkt wyjścia, na którym stosowane są migracje i wykonywane deployDump, czyli base.sql + migracje + deployDump = aktualna struktura bazy danych. Taki plik można wygenerować za pomocą narzędzia pg_dump. Używane jest base.sql wyłącznie przy inicjalizacji bazy danych od zera.

Nazwijmy skrypt pełnej inicjalizacji bazy danych refresh.sh. Proces roboczy może wyglądać następująco:

  1. Programista uruchamia w swoim środowisku refresh.sh i otrzymuje aktualną strukturę bazy danych
  2. Programista zaczyna pracę nad zadaniem, modyfikując lokalną bazę danych zgodnie z potrzebami nowej funkcjonalności (ALTER TABLE ... ADD COLUMN itd.)
  3. Po zakończeniu zadania programista wywołuje funkcję , która zapisuje strukturę wszystkich obiektów z bazy danych w postaci osobnych plików tekstowych. Na wyjściu tworzony jest katalog zawierający strukturę bazy danych, podzieloną na pogrupowane pliki, które łatwo dodać do VCS., aby zarejestrować w VCS zmiany dokonane w bazie danych
  4. Programista ponownie uruchamia refresh.sh, następnie verifyDump, który teraz pokazuje listę zmian do uwzględnienia w migracji
  5. Programista przenosi wszystkie zmiany strukturalne do pliku migracji, uruchamia jeszcze raz refresh.sh i verifyDump, a jeśli migracja zostanie poprawnie utworzona, verifyDump pokaże brak różnic między lokalną bazą danych a zapisanym zrzutem.

Opisana wyżej procedura jest zgodna z zasadami gitflow. Każda gałąź w VCS będzie zawierać swoją wersję dumpa, a podczas scalania gałęzi nastąpi scalanie dumpów. W większości przypadków po scaleniu nie trzeba podejmować żadnych dodatkowych działań, ale jeżeli w różnych gałęziach wprowadzono zmiany, na przykład w tej samej tabeli, może wystąpić konflikt.

Rozważmy konfliktową sytuację na przykładzie: jest gałąź develop, od której odgałęziły się dwie gałęzie: feature1 i feature2, które nie mają konfliktów z develop, ale mają konflikty między sobą. Zadaniem jest wykonanie scalania obu gałęzi w develop. W takim przypadku zaleca się najpierw scalić jedną z gałęzi w develop, a następnie scalić develop do pozostałej gałęzi, rozwiązując przy tym konflikty w pozostałej gałęzi, a następnie wykonać scalanie ostatniej gałęzi w develop. Na etapie rozwiązywania konfliktów może być konieczne poprawienie pliku migracji w ostatniej gałęzi, aby odpowiadał on ostatecznemu dumpowi, który uwzględnia wyniki scalenia.

SchemaKeeper

Dzięki obecności w VCS dumpa aktualnej struktury bazy danych istnieje możliwość sprawdzenia bazy produkcyjnej pod kątem dokładnego dopasowania do wymaganej struktury. Gwarantuje to, że wszystkie zmiany, które zaplanowali deweloperzy, zostały pomyślnie przeniesione na bazę produkcyjną.

Ponieważ DDL w PostgreSQL jest transakcyjny, zaleca się stosowanie następującej kolejności wdrożenia, aby w przypadku nieprzewidzianego błędu, "bezboleśnie" wykonać ROLLBACK:

  1. Rozpocznij transakcję
  2. W transakcji wykonaj wszystkie migracje
  3. W tej samej transakcji wykonaj deployDump
  4. Nie kończąc transakcji, wykonaj verifyDump. Jeśli nie ma błędów, wykonaj COMMIT. Jeśli są błędy, wykonaj ROLLBACK

Te kroki są wystarczająco łatwe do włączenia w istniejące podejścia do wdrażania aplikacji, w tym zero-downtime.

Podsumowanie

Dzięki opisanym powyżej metodom można wycisnąć maksimum wydajności z projektów "PHP + PostgreSQL", poświęcając przy tym stosunkowo niewielką ilość wygody programowania w porównaniu z wdrożeniem całej logiki biznesowej w podstawowym kodzie aplikacji. Co więcej, przetwarzanie danych w . Testowanie z innymi językami nie było przeprowadzane, dlatego użycie może być mniej efektywne lub niemożliwe. często wygląda bardziej przejrzyście i wymaga mniejszej ilości kodu niż ta sama funkcjonalność napisana w PHP.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster