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