Бизнес логика в базата данни с помощта на SchemaKeeper

Целта на тази статия е чрез примера на библиотеката schema-keeper да покаже инструментите, които значително улесняват процеса на разработка на бази данни в рамките на PHP проекти, използващи СУБД PostgreSQL.

Информацията в тази статия ще бъде полезна преди всичко на разработчиците, които желаят да максимално използват възможностите на PostgreSQL, но срещат проблеми с поддръжката на бизнес логиката, изнесена в БД.

Статията няма да описва предимствата или недостатъците на съхранението на бизнес логика в базата данни. Предполага се, че читателят вече е направил своя избор.

Ще бъдат разгледани следните въпроси:

  1. В какъв вид да се съхранява дампът на структурата на БД в системата за контрол на версиите (наричана по-долу VCS)
  2. Как да проследяваме промените в структурата на БД след запазване на дампа
  3. Как да пренесем промените в структурата на БД на други среди без конфликти и огромни файлове за миграция
  4. Как да организираме процеса на паралелна работа по проекта от няколко разработчици
  5. Как безопасно да внедряваме повече промени в структурата на БД на производствена среда

    SchemaKeeper е проектиран да работи с хранимите процедури, написани на езика PL/pgSQL. Тестването с други езици не е проведено, следователно употребата може да бъде по-малко ефективна или невъзможна.

В какъв вид да се съхранява дампът на структурата на БД в VCS

Библиотека schema-keeper предоставя функция saveDump, която запазва структурата на всички обекти от БД под формата на отделни текстови файлове. В изхода се създава директория, съдържаща структурата на БД, разделена на групирани файлове, които лесно могат да се добавят в VCS.

Нека разгледаме преобразуването на обекти от БД в файлове с няколко примера:

Тип обект
Схема
Име
Относителен път до файла

Таблица
public
accounts
./public/tables/accounts.txt

Хранима процедура
public
auth(hash bigint)
./public/functions/auth(int8).sql

Представяне
booking
tariffs
./booking/views/tariffs.txt

Съдържанието на файловете представлява текстово представяне на структурата на конкретния обект от БД. Например, за хранимите процедури съдържанието на файла ще бъде пълната дефиниция на хранимата процедура, започваща с блока CREATE OR REPLACE FUNCTION.

Както може да се види от таблицата по-горе, пътят до файла съдържа информация за типа, схемата и името на обекта. Този подход улеснява навигацията в дампа и проверката на кода на промените в БД.

Разширение .sql за файловете с изходен код на съхранявани процедури е избрано, за да могат IDE автоматично да предоставят инструменти за взаимодействие с БД при отваряне на файла.

Как да проследяваме промените в структурата на БД след запазване на дампа

Запазвайки дамп на текущата структура на БД в VCS, получаваме възможност да проверим дали са направени промени в структурата на базата след създаването на дампа. В библиотеката schema-keeper за идентифициране на промените в структурата на БД е предвидена функция verifyDump, която без странични ефекти връща информация за разликите.

Алтернативен начин за проверка е повторно да извикате функцията saveDump, посочвайки същата директория, и да проверите наличието на промени в VCS. Тъй като всички обекти от БД са запазени в отделни файлове, VCS ще покаже само променените обекти.
Основният минус на този метод е необходимостта от презаписване на файловете, за да видите промените.

Как да пренесем промените в структурата на БД на други среди без конфликти и огромни файлове за миграция

Благодарение на функцията deployDump изходният код на съхраняваните процедури може да се редактира по същия начин, както обикновения изходен код на приложението. Можете да добавяте/изтривате нови редове в кода на съхраняваните процедури и незабавно да изпращате промените в системата за контрол на версиите, или да създавате/изтривате съхранявани процедури чрез създаване/изтриване на съответните файлове в директорията с дампа.

Например, за да създадете нова съхранявана процедура в схемата public , е достатъчно да създадете нов файл с разширение .sql в директорията public/functions, да поставите в него изходния код на съхраняваната процедура, включително блока CREATE OR REPLACE FUNCTION, след това да извикате функцията deployDump. По подобен начин се извършва промяната и изтриването на съхраняваната процедура. Така кодът попада едновременно и в VCS, и в базата данни.

Ако в изходния код на някоя съхранявана процедура се появи грешка или несъответствие между имената на файла и съхраняваната процедура, то deployDump няма да се изпълни, показвайки текста на грешката. Несъответствието на съхраняваните процедури между дампа и текущата БД е невъзможно при използване на deployDump.

При създаването на нова съхранявана процедура няма нужда ръчно да въвеждате правилното име на файла. Достатъчно е файлът да има разширение .sql. След извикването на deployDump текстът на грешката ще съдържа правилното име, което може да се използва за преименуване на файла.

deployDump позволява да се променят параметрите на функцията или типа на връщаната стойност без допълнителни действия, докато при класическия подход първо трябваше да се
изпълни DROP FUNCTION, а след това CREATE OR REPLACE FUNCTION.

За съжаление, има ситуации, когато deployDump не можем автоматично да приложим промените. Например, ако бъде изтрита триггерна функция, която се използва поне от един триггер. Тези ситуации се решават ръчно чрез миграционни файлове.

Ако за пренасянето на промените в хранимите процедури отговаря самият schema-keeper, то за пренасянето на останалите промени в структурата е необходимо да се използват миграционни файлове. Например, добра библиотека за работа с миграции е doctrine/migrations.

Миграциите трябва да се прилагат преди стартиране deployDump. Това позволява да се внесат всички промени в структурата и да се разрешат проблемните ситуации, така че промените в хранимите процедури след това да се пренесат без проблем.

По-подробно работата с миграции ще бъде описана в следващите раздели.

Как да организираме процеса на паралелна работа по проекта от няколко разработчици

Необходимо е да се създаде скрипт за пълна инициализация на БД, който да бъде стартиран от разработчика на неговата работна машина, приводейки структурата на локалната БД в съответствие с запазения в VCS дъмп. Най-лесно е да се раздели инициализацията на локалната БД на 3 стъпки:

  1. Импорт на файл с основната структура, който ще се нарича например, base.sql
  2. Прилагане на миграции
  3. Извикването deployDump

base.sql — това е отправна точка, върху която се прилагат миграции и се изпълнява deployDump, тоест base.sql + миграции + deployDump = актуалната структура на БД. Такъв файл може да бъде форматиран с помощта на утилита pg_dump. Използва се base.sql изключително при инициализация на базата данни от нулата.

Нека наречем скрипта за пълна инициализация на БД refresh.sh. Работният процес може да изглежда по следния начин:

  1. Разработчикът стартира в своето окружение refresh.sh и получава актуалната структура на БД
  2. Разработчикът започва работа по поставената задача, модифицирайки локалната БД според нуждите на новата функционалност (ALTER TABLE ... ADD COLUMN и т.н.)
  3. След изпълнението на задачата разработчикът извиква функцията saveDump, за да запази в VCS промените, направени в БД
  4. Разработчикът отново стартира refresh.sh, след това verifyDump, който сега показва списъка с промените за включване в миграцията
  5. Разработчикът пренася всички промени в структурата в миграционен файл, стартира отново refresh.sh и verifyDump, и ако миграцията е съставена правилно, verifyDump ще покаже липса на разлики между локалната БД и запазения дъмп.

Представеният по-горе процес е съвместим с принципите на gitflow. Всяко клонче в VCS ще съдържа своя версия на дампа, и при сливане на клоновете ще се извършва сливане на дамповете. В повечето случаи след сливането не е нужно да се предприемат допълнителни действия, но ако в различни клонове са направени изменения, например, в една и съща таблица, може да възникне конфликт.

Нека разгледаме конфликтна ситуация на примера: има клон develop, от който са отклонени два клона: feature1 и feature2, които нямат конфликти помежду си с develop, но имат конфликти помежду си. Целта е да се извърши сливане на двата клона в develop. За този случай се препоръчва първо да се извърши сливане на единия клон в develop, а след това сливането на develop в оставащия клон, разрешавайки конфликти в оставащия клон, след което да се извърши сливането на последния клон в develop. На етапа на разрешаване на конфликтите може да се наложи да се коригира файлът за миграция в последния клон, така че да съответства на финалния дамп, включващ резултатите от сливанията.

Как безопасно да внедряваме повече промени в структурата на БД на производствена среда

Благодарение на наличието в VCS на дамп с актуалната структура на БД, се създава възможност за проверка на production базата за точно съответствие с изискваната структура. Това гарантира, че на production базата успешно са пренесени всички промени, които разработчиците са замисляли.

Тъй като DDL в PostgreSQL е транзакционен, препоръчително е да се спазва следният ред на деплой, за да може, в случай на непредвидена грешка, да се извърши "безболезнено" ROLLBACK:

  1. Да започнем транзакция
  2. В транзакцията да се извършат всички миграции
  3. В тази съща транзакция да се извърши deployDump
  4. Не завършвайки транзакцията, да се извърши verifyDump. Ако няма грешки, да се извърши COMMIT. Ако има грешки, да се извърши ROLLBACK

Тези стъпки лесно могат да се интегрират в съществуващите подходи за деплой на приложения, включително zero-downtime.

Заключение

Благодарение на гореописаните методи, е възможно да се извлече максимална производителност от проектите „PHP + PostgreSQL“, жертвайки относително малко удобство в разработката в сравнение с реализирането на цялата бизнес логика в основния код на приложението. Освен това, обработката на данни в PL/pgSQL често изглежда по-прозрачно и изисква по-малко код, отколкото същата функционалност, написана на PHP.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster