DBIx :: Class to popularny interfejs Perla do dowolnej bazy danych, z którą można się połączyć za pośrednictwem DBI . Istnieje dobra dokumentacja zawierająca szczegółowe informacje techniczne, ale mało informacji na temat jego prawidłowego wykorzystania (w tym sytuacji, w których prawdopodobnie nie chcesz).
W wielu sytuacjach ludzie sięgają po niego odruchowo, ponieważ uważają, że powinni go używać do wszystkiego, co dotyczy bazy danych. Jednak najczęściej widziałem, że jest nadużywane do tego stopnia, że staje się punktem bólu. Moje pytanie podczas recenzji kodu i architektury zawsze brzmi: „Jakie korzyści daje Foo?” Najczęściej programiści, których widzę w takich sytuacjach, nie mogą na to udzielić spójnej odpowiedzi. Ale często też nie rozumieją prostego SQL.
Od kilku miesięcy pytam ludzi „Dlaczego korzystasz z DBIx :: Class?” i otrzymałem tylko jedną dobrą odpowiedź (i ta osoba była również w stanie odpowiedzieć na pytanie „Kiedy nie użyjesz”). Peter Rabbitson, główny programista, zbliżył się do odpowiedzi w swoim wywiadzie dla FLOSS Weekly , ale jest to nieco zakopane w środku wywiadu.
Jak więc zdecydować, czy użycie DBIx :: Class jest odpowiednie dla projektu?
Odpowiedzi:
Zanim odpowiem na pytanie, wydaje mi się, że pewne tło jest w porządku.
Rdzeń problemu
Po latach wywiadów i zatrudniania programistów nauczyłem się dwóch rzeczy:
Zdecydowana większość programistów ma bardzo małe doświadczenie w projektowaniu baz danych.
Zauważyłem luźną korelację między tymi, którzy nie rozumieją baz danych, a tymi, którzy nienawidzą ORM.
(Uwaga: i tak, wiem, że są tacy, którzy bardzo dobrze rozumieją bazy danych i nienawidzą ORM)
Kiedy ludzie nie rozumieją, dlaczego klucze obce są ważne, dlaczego nie umieścić nazwę producenta w
item
tabeli, ani dlaczegocustomer.address1
,customer.address2
icustomer.address3
pola nie są dobrym pomysłem, dodając ORM aby łatwiej dla nich pisać błędów bazy danych nic nie pomoże.Zamiast tego, z odpowiednio zaprojektowaną bazą danych i przykładem użycia OLTP, ORM są złote. Większość pracy w chrząstce znika, a dzięki narzędziom takim jak DBIx :: Class :: Schema :: Loader mogę przejść od dobrego schematu bazy danych do działającego kodu Perla w kilka minut. Przywołałbym zasadę Pareto i powiedziałbym, że 80% moich problemów rozwiązano przy 20% pracy, ale w rzeczywistości uważam, że korzyści są jeszcze większe.
Nadużywanie rozwiązania
Innym powodem, dla którego niektórzy ludzie nienawidzą ORM, jest to, że pozwalają wyciek abstrakcji. Rozważmy typowy przypadek aplikacji internetowych MVC. Oto coś, co zwykle widzimy (pseudo-kod):
Ludzie piszą takie trasy kontrolerów i klepią się po plecach, myśląc, że to dobry, czysty kod. Byliby wstrząśnięci twardym kodowaniem SQL w swoich kontrolerach, ale zrobili niewiele więcej niż ujawnienie innej składni SQL. Ich kod ORM musi zostać zepchnięty do modelu, a następnie mogą to zrobić:
Wiesz co się teraz stało? Właściwie zamknąłeś model, nie ujawniłeś ORM, a później, gdy okaże się, że możesz pobrać te dane z pamięci podręcznej zamiast z bazy danych, nie musisz zmieniać kodu kontrolera (i jest to łatwiejsze napisać dla niego testy i ponownie użyć logiki).
W rzeczywistości dzieje się tak, że ludzie wyciekają kod ORM na wszystkie kontrolery (i widoki), a kiedy napotykają problemy ze skalowalnością, zaczynają obwiniać ORM, a nie swoją architekturę. ORM dostaje zły rap (widzę to wielokrotnie dla wielu klientów). Zamiast tego ukryj tę abstrakcję, aby po prawdziwym przekroczeniu limitów ORM możesz wybrać odpowiednie rozwiązania dla swojego problemu, zamiast pozwolić, aby kod był tak ściśle powiązany z ORM, że jesteś związany.
Raportowanie i inne ograniczenia
Jak wyjaśnił powyżej Rob Kinyon, raportowanie jest zwykle słabą stroną ORM. Jest to podzbiór większego problemu, w którym skomplikowany SQL lub SQL obejmujący wiele tabel czasami nie działa dobrze z ORM. Na przykład czasami ORM wymusza typ łączenia, którego nie chcę i nie mogę powiedzieć, jak to naprawić. A może chcę użyć podpowiedzi do indeksu w MySQL, ale nie jest to łatwe . A czasem SQL jest tak cholernie skomplikowany, że fajniej byłoby napisać SQL niż dostarczoną abstrakcję.
Jest to jeden z powodów, dla których zacząłem pisać DBIx :: Class :: Report . Jak dotąd działa dobrze i rozwiązuje większość problemów, które mają tutaj ludzie (o ile są w porządku z interfejsem tylko do odczytu). I chociaż w rzeczywistości wydaje się to kulą, o ile nie przeciekasz abstrakcji (jak wyjaśniono w poprzedniej sekcji), sprawia, że praca z nią jest
DBIx::Class
jeszcze łatwiejsza.Kiedy więc wybrać DBIx :: Class?
Dla mnie najczęściej wybrałbym interfejs do bazy danych. Używam go od lat. Jednak mogę nie wybrać go dla systemu OLAP, a nowi programiści z pewnością będą mieli z tym problem. Często też uważam, że potrzebuję metaprogramowania i chociaż
DBIx::Class
zapewnia narzędzia, są one bardzo słabo udokumentowane.Klucz do
DBIx::Class
prawidłowego korzystania jest taki sam, jak w przypadku większości ORM:Nie wyciekaj z abstrakcji.
Napisz swoje przeklęte testy.
W razie potrzeby umieć przejść do SQL.
Dowiedz się, jak znormalizować bazę danych.
DBIx::Class
, gdy się go nauczysz, zajmie się większością ciężkiego podnoszenia i sprawia, że szybkie pisanie aplikacji jest dziecinnie proste.źródło
#dbix-class
i#catalyst
) - kluczem do bitu „nie wyciekać abstrakcji” jest to, że każda rzecz, nad którą pracujesz w DBIC, to podklasa czegoś, co zapewnia zachowanie obcinania plików cookie. Zdecydowanie zachęca się do dodawania metod do podklas i jeśli nie wykonujesz zadania Q&D, tylko metody, które napisałeś, powinny stanowić część interfejsu publicznego.Aby wiedzieć, kiedy użyć czegoś, ważne jest, aby zrozumieć, jaki jest cel rzeczy. Jaki jest cel tego produktu.
DBIx :: Class jest ORM - Object-Relational Mapper. ORM pobiera struktury danych relacyjnej bazy danych oparte na relacjach / zestawach i mapuje je na drzewo obiektów. Tradycyjne mapowanie to jeden obiekt na wiersz, przy użyciu struktury tabeli jako opisu klasy. Relacje rodzic-dziecko w bazie danych są traktowane jako zawieranie relacji między obiektami.
To są jej kości. Ale to nie pomaga ci zdecydować, czy powinieneś użyć ORM. ORM są przede wszystkim przydatne, gdy spełnione są następujące warunki:
Największą siłą ORM jest konstruowanie dobrego SQL-a, aby przejść wykres drzewa nałożony na relacyjną strukturę danych. SQL jest często włochaty i skomplikowany, ale taka jest cena zarządzania niedopasowaniem impedancji.
Podczas gdy ORM są bardzo dobre w pisaniu SQL do ekstrakcji wierszy, są bardzo słabe w pisaniu SQL do zestawiania. Jest to typ SQL, na którym budowane są raporty. Ten rodzaj zestawiania jest budowany przy użyciu różnych narzędzi, a nie ORM.
Istnieje wiele ORM w różnych językach, kilka w Perlu. Inni twórcy map to Class :: DBI i Rose :: DB. DBIx :: Class jest często uważany za lepszy od innych, w dużej mierze na podstawie jego zestawów wyników. Jest to koncepcja, w której generowanie SQL jest oddzielone od wykonywania SQL.
Aktualizacja : W odpowiedzi na Ovid, DBIx :: Class (poprzez SQL :: Abstract) zapewnia możliwość zarówno określenia, które kolumny mają zostać zwrócone, jak i jakich wskazówek indeksu użyć.
Ogólnie jednak, jeśli chcesz to zrobić, lepiej nie używać ORM dla tego konkretnego zapytania. Pamiętaj - głównym celem ORM jest odwzorowanie wierszy w tabeli na obiekty klasy, których atrybutami są kolumny tabeli. Jeśli wypełniasz tylko niektóre atrybuty, potencjalni użytkownicy tego obiektu nie będą wiedzieli, które atrybuty są wypełnione, czy nie. Prowadzi to do przerażającego programowania obronnego i / lub ogólnej nienawiści do ORM.
Niemal zawsze chęć użycia wskazówek indeksu lub ograniczenia zwracanych kolumn jest albo optymalizacją szybkości i / lub zapytaniem agregującym.
Tak, świetny DBA może tworzyć tabele z funkcją wierszy 100MM + w Oracle lub SQL * Server. Jeśli to czytasz, nie masz świetnego DBA na personel.
Wszystko to mówi, że dobry ORM nie tylko tworzy wykresy obiektowe - zapewnia także introspektywną definicję twojej bazy danych. Możesz to wykorzystać do tworzenia zapytań ad-hoc i korzystania z nich tak, jak w przypadku DBI, bez tworzenia wykresu obiektowego.
źródło
Jako jeden z głównych programistów platformy e-commerce Interchange6 (i podstawowej piły łańcuchowej schematu) mam dość dogłębne doświadczenie z DBIC. Oto kilka rzeczy, dzięki którym jest to świetna platforma:
Generator zapytań pozwala napisać jeden raz dla wielu silników baz danych (i wielu wersji każdego z nich). Obecnie obsługujemy Interchange6 z MySQL, PostgreSQL i SQLite i dodamy obsługę większej liczby silników, gdy tylko zdobędziemy czas i zasoby. Obecnie w całym projekcie są tylko dwie ścieżki kodu, które mają dodatkowy kod uwzględniający różnice między silnikami, co wynika wyłącznie z braku konkretnej funkcji bazy danych (brakuje miejsc SQLite) lub z powodu idiotyzmu MySQL, który się zmienił sposób, w jaki jego funkcja LEAST obsługuje wartości NULL między dwiema mniejszymi wersjami.
Wstępnie zdefiniowane zapytania oznaczają, że mogę budować proste metody, które można wywoływać (z argumentami lub bez) z kodu aplikacji, dzięki czemu moje zapytania są głównie zawarte w definicji schematu zamiast zaśmiecać kod aplikacji.
Komponowalne generowanie zapytań umożliwia podział zapytań na małe, zrozumiałe, predefiniowane zapytania, a następnie połączenie ich w celu utworzenia złożonych zapytań, które byłyby trudne do utrzymania w długim okresie w DBIC (jeszcze gorzej w czystym SQL), gdyby zostały zbudowane w jednym kroku.
Schema :: Loader pozwolił nam używać DBIC ze starszymi aplikacjami, dając nowy okres życia i znacznie prostszą ścieżkę do przyszłości.
Wtyczki DBIC, DeploymentHandler & Migration ogromnie dodają się do zestawu narzędzi, które upraszczają moje życie.
Jedną z ogromnych różnic między DBIC i większością innych platform podobnych do ORM / ORM jest to, że chociaż stara się prowadzić Cię przez sposób robienia rzeczy, nie powstrzymuje Cię również od robienia szalonych rzeczy, które lubisz:
Możesz korzystać z funkcji SQL i procedur przechowywanych, których DBIC nie zna, po prostu podając nazwę funkcji jako klucz w zapytaniu (może również prowadzić do dobrej zabawy, gdy spróbujesz użyć NAJMNIEJ w MySQL ^^, ale to nie wina DBIC) .
Dosłowny SQL może być użyty, gdy nie ma „sposobu DBIC” na zrobienie czegoś, a zwracany wynik jest nadal zawinięty w ładne klasy z akcesoriami.
TL; DR Prawdopodobnie nie zadałbym sobie trudu, aby użyć go do naprawdę prostych aplikacji z zaledwie kilkoma tabelami, ale kiedy muszę zarządzać czymś bardziej złożonym, szczególnie gdy kluczowa jest kompatybilność między silnikami i długoterminowa konserwacja, wtedy DBIC jest ogólnie moja preferowana ścieżka.
źródło
(Zanim zacznę, powinienem powiedzieć, że to po prostu porównuje opakowania DBI, DBI i oparte na Mojo. Nie mam doświadczenia z żadną inną Perlową ORM, więc nie będę komentował ich bezpośrednio).
DBIC robi wiele rzeczy bardzo dobrze. Nie jestem jej dużym użytkownikiem, ale znam teorię. Wykonuje całkiem niezłą robotę w zakresie generowania SQL, a zwłaszcza (jak już powiedziano) obsługi sprzężeń itp. Może także całkiem ładnie pobierać inne powiązane dane.
Główną zaletą, jaką widzę, jest możliwość BEZPOŚREDNIEGO wykorzystania wyników jako klasy modelu. Jest to również znane jako „dodawanie metod zestawu wyników”, w którym można uzyskać wyniki i wywołać metody na tych wynikach. Typowym przykładem jest pobranie obiektu użytkownika z DBIC, a następnie wywołanie metody w celu sprawdzenia, czy hasło jest prawidłowe.
Pewne wdrożenie schematu może być trudne, ale zawsze jest trudne. DBIC ma narzędzia (niektóre w modułach zewnętrznych), które ułatwiają i prawdopodobnie łatwiej niż ręczne zarządzanie własnymi schematami.
Po drugiej stronie monety znajdują się inne narzędzia, które odwołują się do innych wrażliwości, takich jak opakowania DBI o smaku mojo. Mają urok bycia szczupłym, a jednak wciąż użytecznym. Większość z nich również wzięła wskazówkę z Mojo :: Pg (oryginał) i dodała przydatne funkcje, takie jak zarządzanie schematem w plikach płaskich i integracja z pubsub.
Te moduły o smaku Mojo wyrosły z jednego innego słabego punktu DBIC, a mianowicie, że nie jest (jeszcze) zdolny do wykonywania asynchronicznych zapytań. Autorzy zapewniali mnie, że jest to technicznie możliwe, być może nawet szybko, ale istnieją problemy z zaprojektowaniem odpowiedniego interfejsu API. (Trzeba przyznać, że nawet poproszono mnie o pomoc i chociaż tak zrobię, po prostu nie wiem, jak poruszyć igłą w czasie, który muszę temu poświęcić).
TL; DR używaj DBIC, chyba że kochasz SQL lub potrzebujesz asynchronizacji, w takim przypadku sprawdź opakowania DBI o smaku Mojo.
źródło
Moje przemyślenia na ten temat napisałem w DBIC vs. DBI trzy lata temu. Podsumowując, wymieniłem dwa główne powody:
Jeśli chodzi o anty-wzory, to jedyne, co mogę wymyślić, to wydajność. Jeśli naprawdę chcesz wycisnąć każdy cykl zegara z procesora, być może DBIC nie jest odpowiednim narzędziem do tego zadania. Ale z pewnością w przypadku aplikacji, które piszą, przypadki te są coraz rzadsze. Nie pamiętam, kiedy ostatni raz napisałem nową aplikację, która rozmawiała z bazą danych i nie używała DBIC. Oczywiście pomaga, jeśli wiesz trochę o dostrajaniu zapytań generowanych przez DBIC.
źródło
Sposób, w jaki go skaluję:
utwórz jedną klasę, która udostępnia konstruktor gniazda DBI i metody testowania.
wyprowadzić tę klasę do klas zapytań SQL (jedna klasa na tabelę sql) i przetestować gniazdo w czasie konstruktora.
użyj zmiennych o zasięgu klasowym do przechowywania nazwy tabeli i nazw kolumn indeksu podstawowego.
Napisz wszystkie swoje tabele interpolujące SQL i główną kolumnę indeksu z tych zmiennych zamiast definiować je statycznie w SQL.
użyj makr edytora, aby umożliwić tworzenie podstawowych par metod DBI (przygotowanie i wykonywanie) podczas wpisywania TYLKO instrukcji sql.
Jeśli możesz to zrobić, możesz pisać czysty kod API na DBI przez cały dzień ze względną łatwością.
Przekonasz się, że wiele zapytań będzie można przenosić na wiele tabel. W tym momencie możesz wyciąć i wkleić do klasy EXPORTER i wrzucić je tam, gdzie to konieczne. Tutaj zaczyna się interpretacja klasowa interpolacji nazwy tabeli i nazw głównych kolumn indeksu.
Zastosowałem to podejście do skalowania do setek metod DBI o stosunkowo dobrej wydajności. Nie chciałbym próbować utrzymywać kodu DBI w żaden inny sposób.
Kiedy używać DBI: Zawsze.
Nie sądzę jednak, żeby to było twoje prawdziwe pytanie. Twoje prawdziwe pytanie brzmiało: „To wygląda jak wielka PITA, proszę powiedz mi, że nie muszę tego robić?”
Ty nie. Rozłóż to poprawnie, a część DBI staje się wystarczająco redundantna, aby móc ją w większości zautomatyzować.
źródło
Nie jestem ekspertem od Perla, ale często go używam. Jest wiele rzeczy, których nie wiem lub nie wiem, jak zrobić lepiej; pewnych rzeczy, których po prostu nie jestem jeszcze w stanie zrozumieć, pomimo dokumentacji.
Zaczynam od DBI, ponieważ myślę: „Och, to prosty projekt, nie potrzebuję nadmiaru ORM i nie chcę mieć problemów z konfiguracją i modułami schematu”. Ale bardzo szybko - prawie za każdym razem - szybko zaczynam przeklinać się za tę decyzję. Kiedy chcę zacząć być kreatywny w moich zapytaniach SQL (zapytania dynamiczne, a nie tylko symbole zastępcze porównania), staram się zachować zdrowie psychiczne przy użyciu DBI. SQL :: Abstract bardzo pomaga i zazwyczaj to mi wystarcza. Ale moja kolejna mentalna walka polega na utrzymywaniu dużej ilości kodu SQL w moim kodzie. Bardzo rozpraszające jest dla mnie to, że linie i wiersze osadzonego SQL są wewnątrz brzydkich heredoków. Może muszę użyć wysokiej jakości IDE.
W końcu, częściej niż nie, trzymam się prostej DBI. Ale wciąż żałuję, że nie ma lepszego sposobu. DBIx :: Class ma kilka naprawdę fajnych cech i korzystałem z niego kilka razy, ale wydaje się tak przesadny w przypadku wszystkich projektów poza największymi. Nie jestem nawet pewien, które zarządzanie jest bardziej kłopotliwe: DBI z rozproszonym SQL lub DBIC z rozproszonymi modułami Schema.
(Och, takie rzeczy jak ograniczenia i wyzwalacze to dla mnie ogromny plus dla DBIC.)
źródło