Firebird, czyli Interbase za darmo
Transkrypt
Firebird, czyli Interbase za darmo
2 / 2 0 0 5 Wszelkie prawa zastrzeżone. Rozpowszechnianie arty kułu bez zgody Software Wy dawnictwo Sp. z o.o. zabronione. S oft w a r e W y da w n ic t w o S p. z o. o. , u l. Lew a r t ow sk ieg o 6 , 0 0 -1 9 0 W a r sza w a , POLS KA . Kon t a k t : Da r iu sz Pa w łow sk i ( dpa w low sk i@ ph psolm a g . or g ) Początki Firebird Firebird, czyli Interbase za darmo Anatol Ogórek Programista PHP najczęściej wybiera MySQL lub PostgreSQL wychodząc z założenia, że produkt najpopularniejszy oznacza najlepszy. Ten warunek nie zawsze jest jednak spełniony. Od 2000 roku bardzo intensywnie rozwijany jest projekt Firebird. Efektem prac jest darmowa, w pełni relacyjna i profesjonalna baza danych, wprost idealna dla webdeweloperów. W SIECI 1. http://www.firebirdsql.com/ – oficjalna strona Firebirda 2. http://ibphoenix.com/ – informacje na temat Interbase/Firebird 3. http://www.interbaseworld.com/ – strona dla użytkowników IB/FB 4. http://www.interbasetools. de/ – strona z narzędziami dla IB/FB (po niemiecku) 5. http://www.fingerbird.de/ – strona dla początkujących użytkowników FB 6. http://ibwebadmin.sourcefo rge.net/ – interfejs webowy do zarządzania FB/IB NA CD Na dołączonym do pisma CD znajdują się wszystkie omawiane w artykule skrypty oraz program instalacyjny Firebirda. 44 Z alet spółki PHP + SQL nie sposób nie docenić. Co ciekawe, wielu webmasterów utożsamia SQL-a z bazą danych MySQL sądząc, że jest to jedyne słuszne rozwiązanie. Niektórzy wykorzystują też coraz popularniejszego SQLite'a lub linuksowego PostgreSQL-a. To jednak nie koniec dobrych rozwiązań. Mało tego, istnieją systemy lepsze, a jednym z nich jest Firebird. Firebird Nazwa Firebird wielu osobom skojarzy się (po części słusznie) z odchudzoną przeglądarką internetową Mozilla, którą nieświadomie ochrzczono w ten sposób. Spowodowało to spore zamieszanie i wiele dyskusji, ponieważ nazwa ta była już wcześniej zajęta przez darmową bazę danych, która mimo wielu zalet ciągle jest niestety mało znana. 25 lipca 2000 roku Borland opublikował kod źródłowy swojej, do dzisiaj bardzo popularnej bazy Interbase na www.phpsolmag.org licencji IPL (InterBase Public License v.1.0). Wtedy na jego podstawie został zapoczątkowany projekt FirebirdSQL, który ma na celu dalsze rozwijanie bardzo już solidnego narzędzia Borlanda. Firebird stał się bazą danych oferowaną na licencji Open Source, a co za tym idzie, zupełnie darmową i do dzisiejszego dnia intensywnie rozwijaną. Co należy wiedzieć? Czytelnikowi przyda się ogólna wiedza na temat relacyjnych baz danych. Powinien też znać podstawy PHP. Co obiecujemy? Z artykułu czytelnik dowie się, jak zbudować aplikację bazodanową w oparciu o Firebirda, z uwzględnieniem takich cech jak transakcyjność, wyzwalacze czy blokady na poziomie wierszy. Powiemy też, dlaczego Firebirda – w przeciwieństwie do MySQL-a – można uważać za w pełni relacyjną bazę danych. PHP Solutions Nr 1/2005 Firebird Dostępny jest na wielu różnych platformach, począwszy od Linuksa, poprzez szereg innych systemów uniksowych i Microsoft Windows, a na Mac OS X kończąc. Przyjrzyjmy się bliżej jego możliwościom. Potęga ognistego ptaka Niewątpliwie za jedną z większych zalet Firebirda można uznać jego łatwość obsługi. Instalacja pod Windows sprowadza się do kilku kliknięć myszką, natomiast w systemach uniksowych wystarczy uruchomić odpowiedni skrypt instalacyjny. Baza potrzebuje bardzo niewielu zasobów systemowych, zarówno jeśli chodzi o miejsce na dysku jak i pamięć operacyjną. Wynika to stąd, że silnik Interbase projektowany był w czasach, gdy komputery nie miały jeszcze tak dużej mocy obliczeniowej jak obecnie. Nie oznacza to, że baza jest prymitywna - wręcz przeciwnie, funkcjonalnością dorównuje wielu komercyjnym i drogim odpowiednikom. Pliki bazy danych mogą być rozmieszczone w wielu różnych miejscach na dysku i nic nie stoi na przeszkodzie, aby przechowywać je na osobnych partycjach. Jest to niewątpliwą zaletą, jeśli spodziewamy się, że nasza baza może w przyszłości osiągnąć duży rozmiar. Kolejną cechą Firebirda jest niemal pełna zgodność ze standardami SQL: zaimplementowano w niej większość cech SQL-89, SQL-92 oraz część właściwości SQL-99. System posiada pełną obsługę złączeń warunkowych i bezwarunkowych (ang. inner join, left join, right join, outer join), unie (ang. unions) i perspektywy (ang. views). Dla użytkowników MySQL-a nowością będzie możliwość korzystania z podzapytań (ang. subqueries). Dodatkowo wsparcie dla pól wyliczanych (ang. calculated fields), procedur składowanych (ang. stored procedures), wyzwalaczy (ang. triggers), wyzwalaczy na perspektywach, więzów (ang. constraints) czy też lokalizacji sprawia, że bazę Firebird można uznać za w pełni profesjonalną. Dla webdeweloperów Firebird świetnie nadaje się do tworzenia dynamicznych serwisów WWW. Ciężko podać przypadek, w którym nie sprostałby naszym wymaganiom. Jeśli potrzebujemy bazy prostej w admini- PHP Solutions Nr 1/2005 Początki Generatory Każda baza danych posiada swój mechanizm nadawania unikalnych identyfikatorów. Przykładowo w MySQL możemy korzystać z pól typu autoincrement, a w Oracle z sekwencji. W Firebirdzie wykorzystuje się generatory. Generator nie jest ściśle powiązany z żadną kolumną, ani nawet z żadną tabelą. Może się zdarzyć, że jeden generator będzie obsługiwał wszystkie tabele naszej bazy. Zwykle jednak przyjmuje się, że istnieje osobny generator dla każdej tabeli, która posiada klucz główny (ang. primary key). Aby stworzyć generator, wystarczy wykonać polecenie: CREATE GENERATOR nazwa_generatora; Następnie, aby nadawanie unikalnych numerów odbywało się automatycznie, można na tabelę założyć wyzwalacz: :SET TERM !! ; CREATE TRIGGER SET_UNIQUE_ID FOR OUR_TABLE BEFORE INSERT AS BEGIN IF (NEW.ID IS NULL) THEN NEW.ID = GEN_ID(OUR_TABLE_GENERATOR, 1); END !! SET TERM ; !! W tym wypadku przed wstawieniem wiersza do tabeli, jeśli pole ID ma wartość NULL nadawana jest mu kolejna wartość generatora. Nie jest jednak konieczne używanie wyzwalaczy. Wartość generatora można również pobrać i wstawić do bazy ręcznie za pomocą funkcji: GEN_ID(nazwa_generatora, skok). Bardzo ważną cechą generatorów jest to, że nie są transakcyjne. Jeśli rozpoczniemy transakcję, pobierzemy kolejną wartość z generatora, a następnie anulujemy transakcję, generator nie cofnie się do poprzedniej wartości. Wbrew pozorom jest to olbrzymia zaleta, ponieważ daje nam stuprocentową pewność, że otrzymamy unikalne ID. stracji, wieloplatformowej, mającej niewielkie wymagania sprzętowe, a do tego darmowej, wybór może być tylko jeden – Firebird. Istnieje oczywiście PostgreSQL, lecz uruchomienie go na systemach innych niż Linux jest dość trudne. PostgreSQL ma też zdecydowanie większe wymagania, jeśli chodzi o zasoby systemowe oraz przestrzeń na dysku, a jego konfiguracja i administracja jest znacznie bardziej skomplikowana. Warto dodać, że tempo rozwoju Firebirda jest zawrotne, a kolejne wersje przynoszą coraz większą funkcjonalność i wydajność systemu. Praktyka Zalety Firebirda można mnożyć bardzo długo. Przejdźmy jednak do konkretów. Załóżmy, że tworzymy serwis wymagający wysokiej niezawodności, bezpieczeństwa oraz kontroli integralności danych. Potrzebujemy więc bazy z doskonałą obsługą transakcyjności. Transakcja to zbiór operacji, których wykonanie musi zakończyć się sukcesem. W przypadku niepowodzenia którejkolwiek z nich wszystkie powinny być anulowane. Transakcje opisuje zasada www.phpsolmag.org ACID – Atomicity, Consistency, Isolation, and Durability: • • • • Atomicity – transakcja może być wykonana tylko w całości albo wcale, Consistency – stan bazy danych zawsze przedstawia stan przed lub po transakcji. Zapytania do systemu w czasie wykonywania transakcji muszą pokazywać stan bazy przed transakcją, Isolation – transakcja zachodzi niezależnie od innych wykonywanych operacji, w tym od innych transakcji, Durability – w przypadku awarii całego systemu bazodanowego transakcje pozostają kompletne. W naszym projekcie MySQL niestety się nie sprawdzi, ponieważ transakcje w tej bazie są dopiero w powijakach. Jeśli dodatkowo system ma być dostępny na różnych platformach systemowych, nie mamy zbyt wielkiego wyboru. Pokażemy teraz, jak w praktyce wygląda wykorzystanie Firebirda z poziomu PHP. Spróbujemy wykorzystać transakcyjność za pomocą funkcji wbudowanych 45 Początki Firebird Listing 1. Tworzymy tabelę INVOICE Listing 2. Tworzymy tabelę POSITIONS oraz generator DROP TABLE INVOICE; CREATE TABLE INVOICE( ID INTEGER NOT NULL PRIMARY KEY, NUMBER varchar(30) default '', DOC_DATE date, SALE_DATE date, CONTRACTOR varchar(250) default '', NETTO NUMERIC(15,2) default 0, VAT NUMERIC(15,2) default 0, GROSS_SUM NUMERIC(15,2) default 0 ); DROP TABLE POSITIONS; CREATE TABLE POSITIONS( id INTEGER NOT NULL PRIMARY KEY, ID_INVOICE INTEGER , ITEM VARCHAR(20) default '', QUANTITY NUMERIC(15,3) default 0, NETTO NUMERIC(15,2) default 0, VAT_RATE NUMERIC(5,2) default 0); DROP GENERATOR INVOICE_GEN; CREATE GENERATOR INVOICE_GEN; w PHP oraz zastosować wyzwalacze i procedury składowane. Zacznijmy więc od podstaw, czyli od instalacji. Instalacja Wersja dla Microsoft Windows rozpowszechniana jest w postaci standardowego instalatora. Jedyna opcja, którą warto zaznaczyć, to copy client library to <system> directory, co spowoduje, że biblioteka FBCLIENT.DLL zostanie skopiowana do katalogu systemowego. Na koniec należy jeszcze zadecydować, czy Firebird ma być uruchamiany jako usługa (Win XP, Win 2000) czy jako aplikacja (Win 9x). Po kilku minutach mamy zainstalowaną i gotową do użycia bazę danych. W przypadku Linuksa po pobraniu i rozpakowaniu pakietu należy z poziomu użytkownika root uruchomić skrypt install.sh, który cały proces instalacji wykona automatycznie. Nasza baza zostanie zainstalowana w katalogu /opt/firebird/. Wszystkie niezbędne narzędzia administracyjne znajdują się w katalogu instalacyjnym, w podkatalogu bin/. Będziemy jeszcze poproszeni o podanie standardowego hasła masterkey dla domyślnego użytkownika SYSDBA (administratora bazy danych). Oczywiście można korzystać z ustawień domyślnych, co pozbawia nas wszelkich dodatkowych czynności administracyjnych, ale nie jest to bezpieczne. Warto zmienić domyślne hasło oraz założyć nowego użytkownika. W tym celu należy skorzystać z polecenia gsec z podkatalogu bin/: ./gsec -user SYSDBA -pass masterkey 46 DROP GENERATOR POSITIONS_GEN; CREATE GENERATOR POSITIONS_GEN; SET TERM !!; create trigger POSITIONS_GEN_ID for POSITIONS BEFORE INSERT POSITION 0 AS BEGIN NEW.id = GEN_ID(POSITIONS_GEN,1); END!! SET TERM ;!! styczność i pewność, że w razie braku miejsca na jednej z partycji, możemy umieścić plik z bazą na nowo dodanym dysku zmieniając jedynie ścieżkę dostępu. W dalszej części artykułu zakładamy, że użytkownik korzysta z systemu Linux (w przypadku systemu Windows zmiany będą niewielkie – w większości wypadków wystarczy jedynie zmodyfikować ścieżki dostępu) oraz że plik invoice.gdb znajduje się w katalogu /opt/firebird. Przykład z życia Załóżmy, że piszemy skrypt do wystawiania faktur VAT. Tworzymy więc pliki invoice.sql (Listing 1) oraz positions.sql (Listing 2) i wykonujemy dodając do bazy nowe tabele: Następnie możemy zmienić hasło administratora: /opt/firebird/bin/isql -u foo S /opt/firebird/bin/isql -u foo GSEC>modify SYSDBA -pw nowe_hasło S -p bar /opt/firebird/ invoices.gdb<INVOICE.SQL -p bar /opt/firebird/ S S invoices.gdb<POSITIONS.SQL oraz dodać nowego użytkownika foo z hasłem bar: Po tych czynnościach możemy utworzyć nową bazę danych, której właścicielem będzie użytkownik foo. Można to zrobić z poziomu konsoli isql: Zakładamy, że użytkownik wprowadził już dane. Pora wykorzystać PHP i połączyć się z Firebirdem – spójrzmy zatem na Listing 3. Do nawiązania połączenia służy funkcja ibase _ connect(). Teraz musimy zapisać dane do tabel. Aby mieć pewność, że dane zostały zapisane poprawnie, musimy w tym miejscu rozpocząć transakcję: ./isql $tr = ibase_trans($dbh); GSEC>add foo -pw bar GSEC>quit SQL>CREATE DATABASE 'invoice.gdb' S USER 'foo' PASSWORD 'bar'; Na dysku została utworzona baza danych – plik invoice.gdb. Firebird pozwala dodatkowo na skopiowanie tego pliku w dowolne miejsce na dysku – stanowi to jego olbrzymią zaletę. Wystarczy, że w ścieżce do bazy podczas połączenia wpiszemy: localhost:/sciezka/do/pliku/ S invoice.gdb S Po tej czynności możemy przejść do właściwych operacji, czyli zapisu danych. Zakładamy, że dane faktury znajdują się w tablicy asocjacyjnej, której pola mają takie same nazwy jak pola tabeli w bazie danych. Na początku musimy zapisać ogólne dane dotyczące faktury do tabeli INVOICE . W tym celu należy najpierw pobrać wartość generatora przypisanego do tej tabeli za pomocą zapytania: select GEN_ID(INVOICE_GEN, 1) i baza zostanie poprawnie otwarta (zakładając oczywiście, że nadane są prawa do odczytu/zapisu pliku). W ten sposób możemy utworzyć kilka różnych baz danych i rozmieścić je na osobnych partycjach. Daje to nam dużą ela- www.phpsolmag.org S FROM RDB$DATABASE Teraz możemy wstawić do bazy dane faktury. Należy wspomnieć, że znaną praktyką jest wstawianie wartości do PHP Solutions Nr 1/2005 Firebird tabeli przed pobraniem wygenerowanego identyfikatora przy pomocy funkcji MAX(nazwa _ pola). W przypadku aplikacji WWW postępowanie takie jest bardzo niebezpieczne, ponieważ może się okazać, że otrzymaliśmy identyfikator rekordu, który w międzyczasie wstawił ktoś inny. Wtedy zapisywane w kolejnym kroku pozycje dopisalibyśmy do zupełnie innej faktury. Bezpieczeństwo tego typu operacji w znacznej mierze zależy od stosowanego przez bazę danych poziomu izolacji (ang. isolation level). Dla Firebirda domyślnie jest to poziom snapshot (transakcja ma dostęp do wszystkich tabel, lecz nie do zmian wprowadzonych i zatwierdzonych przez inne, rozpoczęte później transakcje), w którym moglibyśmy skorzystać z funkcji MAX() do pobrania identyfikatora ostatnio dodanej pozycji, lecz jeśli przełączylibyśmy poziom izolacji np. na read commited (transakcja ma dostęp do wszystkich tabel i zmian wprowadzonych oraz zatwierdzonych przez inne transakcje) mogłoby się okazać, że nasz program w niektórych przypadkach nie działa poprawnie. Mamy zatem pobrane wcześniej ID faktury – możemy zapisać do bazy wszystkie pozycje tablicy POSITIONS z tym identyfikatorem jako kluczem obcym. Jeśli w trakcie wystąpi błąd zapisu którejkolwiek pozycji, powinniśmy wycofać wszystkie operacje (wraz z zapisaniem danych ogólnych) oraz wyświetlić odpowiedni komunikat błędu. Listing 3. Łączymy się z Firebirdem i wstawiamy dane do bazy <?php $host = 'localhost:/opt/firebird/invoice.gdb'; $username = 'foo'; $password ='bar'; $dbh = ibase_connect($host, $username, $password); if (!$dbh) die ("error connecting to database"); $tr = ibase_trans( $dbh); $invoice = array("NUMBER"=>"2/04/2004", "DOC_DATE"=>"12-04-2004","SALE_DATE"=>"12-04-2004", "CONTRACTOR"=>"Jan Kowalski Sp. z o.o", "NETTO"=>"100","VAT"=>"22","GROSS_SUM"=>"122"); $poz= array( array( "ITEM"=>"Drukarka", "QUANTITY"=>"2", "NETTO"=>"400","VAT_RATE"=>"0.22"), array("ITEM"=>"Monitor", "QUANTITY"=>"1", "NETTO"=>"1200","VAT_RATE"=>"0.22")); // pobieramy wartość pola id przed wstawieniem do bazy $query = 'select GEN_ID(INVOICE_GEN, 1) FROM RDB$DATABASE'; $sth = ibase_query($tr, $query); if (!$sth) database_error ("Błąd przy pobieraniu ID", $tr); $row = ibase_fetch_row($sth); $id = $row[0]; $query = "INSERT INTO INVOICE (ID, NUMBER, DOC_DATE, SALE_DATE, CONTRACTOR, NETTO, VAT, GROSS_SUM) VALUES('$id', '${invoice[NUMBER]}','${invoice[DOC_DATE]}', '${invoice[SALE_DATE]}','${invoice[CONTRACTOR]}', '${invoice[NETTO]}','${invoice[VAT]}','${invoice[GROSS_SUM]}')"; // wstawiamy fakturę do bazy $sth = ibase_query($tr, $query); if (!$sth) database_error ("Błąd przy wstawianiu faktury", $tr); // wstawiamy kolejno wszystkie pozycje faktury for ($a = 0; $a<count( $poz ); $a++) { $query = "INSERT INTO POSITIONS (ID_INVOICE, ITEM, QUANTITY, NETTO) VALUES($id,'".$poz[$a][ITEM]."','".$poz[$a][QUANTITY]."', '".$poz[$a][NETTO]."')"; Wyzwalacze Wyzwalacz (ang. trigger) to specjalna procedura, uruchamiana automatycznie podczas zajścia operacji na bazie danych. W Firebirdzie można tworzyć wyzwalacze uruchamiane przed lub po wstawianiu (INSERT), modyfikacji (UPDATE) lub skasowaniu (DELETE) rekordu. Wyzwalacze nie służą jedynie go generowania unikalnych identyfikatorów. Można je wykorzystać do wielu różnych celów – na przykład do obsługi pól automatycznie wyliczanych, jednak głównym ich zadaniem jest zapewnienie spójności danych w bazie. Na przykład, po skasowaniu faktury, powinny również zostać usunięte wszystkie jej pozycje. W tym celu możemy stworzyć odpowiedni wyzwalacz, który pobierze identyfikator usuniętego rekordu i skasuje wszelkie pozycje z takim kluczem obcym – Listing 4. Po dodaniu takiego wyzwalacza PHP Solutions Nr 1/2005 Początki } $sth = ibase_query($tr, $query); if (!$sth) database_error ("Błąd przy wstawianu pozycji", $tr); // wszystko poszło OK. Zatwierdzamy transakcję. ibase_commit($tr); echo ("Fakturę dodano pomyślnie"); // funkcja obsługująca błędy function database_error ($error, $transaction) { // wycofujemy transakcję ibase_rollback($transaction); } // i kończymy działanie skryptu komunikatem o błędzie die($error); ?> www.phpsolmag.org 47 Początki Firebird Listing 4. Wyzwalacz, który usunie wszystkie pozycje faktury z danym kluczem obcym DROP trigger delete_invoice; SET TERM !!; create trigger delete_invoice for invoice AFTER DELETE AS BEGIN delete from positions where id_invoice=OLD.ID; END!! SET TERM ;!! możemy wejść do konsoli isql i usunąć ręcznie jedną z wstawionych wcześniej faktur. Przekonamy się, że pozycje będą kasowane automatycznie. Procedury składowane Użytkownicy mający doświadczenie w pracy z dużymi środowiskami bazodanowymi zapewne nieraz korzystali z procedur składowanych (ang. stored procedures). Są to procedury pisane w wewnętrznym języku bazy danych, parsowane i kompilowane jednorazowo przed pierwszym wykonaniem. Zastosowanie ich znacząco odciąży naszą aplikację, przyspieszy jej działanie i zwiększy bezpieczeństwo. W Firebirdzie również możemy pisać takie procedury przy użyciu języka PSQL, który, choć może mniej rozbudowany od swoich odpowiedników w ORACLE czy PostgreSQL, spełnia wymagania większości użytkowników. Dodatkowo, Firebird pozwala na tworzenie funkcji UDF (User Defined Functions). Są one pisane w zewnętrznym języku (np. C/C++ lub Delphi), a następnie kompilowane do postaci bibliotek współdzielonych (*.dll lub *.so). Biblioteki te ładowane są do bazy danych, po czym można z nich korzystać z poziomu SQL-a. Procedury składowane w połączeniu z funkcjami UDF mogą przerzucić część ciężaru czasochłonnych operacji na silnik bazy danych, a co za tym idzie – dodatkowo zwiększyć wydajność aplikacji. Blokady na poziomie wierszy MySQL domyślnie oferuje blokady wyłącznie na poziomie tabel. W przypadku bardzo obciążonych serwisów metoda taka jest dalece nieefektywna. Mechanizm transakcji w Firebirdzie 48 działa zupełnie inaczej. Domyślnie każda transakcja „widzi” swoją wersję rekordu z chwili, kiedy została rozpoczęta. Zmiany wprowadzone przez inne transakcje nie są widoczne, dopóki transakcje nie zostaną zatwierdzone (commit). Najlepiej zobrazuje to poniższy przykład: Otwieramy pierwszą sesję, która modyfikuje pozycję z tabeli BOOK : 1 Session #1: Session #2: SQL> select * from book; SQL> select * from book; ID ID TITLE Lord of the rings Widać, że każda z sesji posiada odrębne wersje rekordów widoczne w ramach swojej transakcji. Zatwierdźmy teraz wprowadzone zmiany: Session #1: SQL> commit; SQL> commit; TITLE ============ ========== ============ ========== 1 1 Lord of the rings SQL> update book set title = 'Harry Potter' where id = 1; SQL> select * from title; ID TITLE ============ ========== 1 Harry Potter Na poziomie tej sesji, zawartość tabeli została zmodyfikowana. Otwieramy drugą sesję, która odwołuje się do tej samej tabeli: Session #2: SQL> select * from book; ID TITLE ============ ========== Harry Potter Jak widać. niezatwierdzona transakcja z sesji pierwszej nie zabroniła dostępu do danych transakcji z sesji drugiej, jednakże widoczne były nieuaktualnione (stare) dane. Innym bardzo ważnym mechanizmem blokowania dostępu do rekordów jest select for update. Ta metoda gwarantuje, że żadna inna sesja nie zmieni wybranych danych, dopóki sesja blokująca nie zakończy ich przetwarzania (czyli nie zatwierdzi transakcji). Spójrzmy na poniższy przykład: Session #1: SQL> select * from book where id = 1 for update Pseudorelacyjność – Firebird kontra MySQL Klucze obce służą do tworzenia połączeń relacyjnych (relacji – stąd właśnie pochodzi nazwa relacyjna baza danych) pomiędzy tabelami. W większości przypadków dopasowywane pola to: klucz podstawowy (primary key) z głównej tabeli, który dostarcza unikatowego identyfikatora, dla klucza obcego z każdego rekordu w drugiej tabeli. Weźmy bazę danych dokumentów z księgowości – tabele dokumenty i kontrahenci: tabela dokumenty zawiera m. in. kolumny id _ dokumentu (klucz główny), numer, data, kontrahent, a tabela kontrahenci: kolumny id _ kontrahenta (klucz główny), nazwisko, adres, telefon, email, itp. Kolumna dokumenty.kontrahent może być kluczem obcym odnoszącym się do kolumny kontrahenci.id _ kontrahenta. Unika się w ten sposób powielania tych samych danych w różnych tabelach, co m. in. ułatwia utrzymanie zgodności pomiędzy zawartością bazy danych, a stanem faktycznym. Nic nie stoi na przeszkodzie, aby taką relację stworzyć bez kluczy głównych/obcych, lecz wtedy nie będzie zachowana pełna integralność danych. Dzięki kluczom silnik bazy danych dba o to, aby do tabeli podrzędnej możliwe było wstawienie jedynie rekordów, które mają przyporządkowany wpis w tabeli głównej. Niemożliwe będzie również usunięcie rekordu z tabeli głównej, jeśli nie zostały wcześniej usunięte wszystkie przyporządkowane mu rekordy z tabeli podrzędnej. MySQL nie posiada pełnego wsparcia dla mechanizmu kluczy głównych, dlatego często bywa nazywany pseudorelacyjną bazą danych. Częściowa implementacja dostępna jest jedynie dla tabel typu InnoDB. Firebird oferuje pełne wsparcie dla kluczy obcych, wraz ze sprawdzaniem więzów integralności. www.phpsolmag.org PHP Solutions Nr 1/2005 Firebird with lock; ID TITLE ============ ========== 1 Lord of the rings Session #2: SQL> update book set title = 'PHP Solutions' where id = 1; (Blokada) Jak widać, w tym wypadku druga sesja nie może modyfikować nawet swojej wersji rekordu. Może tego dokonać dopiero po zatwierdzeniu transakcji w obu sesjach. Należy zaznaczyć, że takie sterowanie dostępem do rekordów równie dobrze możemy zastosować z poziomu PHP. MySQL nie oferuje tak rozbudowanego mechanizmu obsługi transakcji, nawet jeśli korzystamy z tabel typu InnoDB. Abstrakcyjny dostęp do Firebirda Wielu webmasterów przyzwyczaiło się już do korzystania z abstrakcyjnych metod dostępu do bazy danych. Nie ma w tym nic dziwnego, jako że w PHP obsługa każdej bazy danych odbywa Listing 5. Przykład połączenia z bazą przy użyciu biblioteki PEAR <?php require_once("PEAR.php"); require_once("DB.php"); $dsn = array( 'phptype' => 'ibase', 'username' => 'foo', 'password' => 'bar', 'hostspec' => 'localhost', 'database' => '/opt/ firebird/invoice.gdb', ); $options = array( 'persistent' => true ); $db = DB::connect($dsn,$options); $sql = "select * from invoice"; $result = $db->query($sql); $row = $result->fetchRow(); print_r ($row); $db->disconnect(); ?> PHP Solutions Nr 1/2005 Początki Listing 6. Przykład połączenia z bazą przy użyciu biblioteki ADOdb <? include("adodb.inc.php"); $db = NewADOConnection('firebird'); $db->Connect("localhost", "foo", "bar", "/opt/firebird/.gdb"); $result = $db->Execute("SELECT * FROM POSITONS"); if ($result === false) die("Błąd"); while (!$result->EOF) { for ($i=0, $max=$result->FieldCount(); $i < $max; $i++) print $result->fields[$i].' '; $result->MoveNext(); print "<br>"; } ?> się za pomocą osobnych funkcji. Jeśli potrzebujemy przenośności kodu oraz niezależności od bazy danych, powinniśmy skorzystać z bibliotek takich jak AdoDB czy PEAR:DB. Zobaczmy, jak interfejsy te radzą one sobie z Firebirdem. Firebird i PEAR:DB PEAR to zbiór bibliotek i rozszerzeń PHP będących odpowiednikiem perlowskiego CPAN, dzięki którym budowa nawet skomplikowanej aplikacji staje się o wiele prostsza. PEAR dołączany jest do każdej oficjalnej dystrybucji PHP, dzięki czemu pisany przez nas kod staje się w pełni przenośny. Jednym z komponentów tej biblioteki jest również klasa DB, która zapewnia zunifikowane API obsługi baz danych. Wśród wielu wspieranych baz jest również Firebird/Interbase. Jeśli wcześniej tworzyliśmy swoje projekty przy użyciu tej biblioteki można modyfikując kilka linijek kodu dostosować je do współpracy z Firebirdem. Na Listingu 5 przedstawiliśmy przykład połączenia z bazą przy użyciu biblioteki PEAR. Wygląda ono podobnie, jak w przypadku innych baz danych. Tworzymy DSN (Data Source Name) i wypełniamy go odpowiednimi parametrami. W przypadku Firebirda (Interbase) dobrze jest przekazać DSN w postaci obiektu, a nie łańcucha. W przeciwnym wypadku mogą wystąpić problemy z połączeniem. Następnie tworzymy obiekt $options, który do prawidłowego połączenia z bazą danych musi zawierać pole: persistent => true; www.phpsolmag.org Do danych odwołujemy się w identyczny sposób jak w przypadku innych baz obsługiwanych przez PEAR:DB. Firebird i AdoDB Skrót ADODB oznacza Active Data Objects DataBase (Obiektowa Baza Danych). W uproszczeniu można powiedzieć, że jest odpowiednikiem PEAR:DB. Również ta biblioteka wśród szerokiej gamy obsługiwanych baz oferuje dostęp do Firebirda. Na Listingu 6 przedstawiliśmy prosty przykład połączenia z bazą danych. Jeśli ktoś korzystał już z tej biblioteki, na pewno nie będzie miał problemów z przesiadką na Firebirda. Wszystkich spragnionych dodatkowej wiedzy na temat AdoDB odsyłamy do artykułu AdoDB – interfejsowa alternatywa z numeru 4/2004, gdzie bardzo dokładnie opisywaliśmy implementację aplikacji bazodanowej w oparciu o interfejs AdoDB. Podsumowanie Jak pokazaliśmy w artykule, Firebird imponuje funkcjonalnością znaną niemal jedynie z komercyjnych baz takich jak ORACLE czy SyBase. Jego licencja (IPL) pozwala na dowolne wykorzystanie programu również w projektach komercyjnych. Prostota instalacji i administracji, niewielkie wymagania sprzętowe oraz wysoka wydajność i niezawodność sprawiają, że przy rozpoczynaniu kolejnego projektu warto pomyśleć o Firebirdzie jako dobrej alternatywie dla MySQL czy PostgreSQL. n 49