You are on page 1of 41

PHP i Oracle.

Tworzenie
aplikacji webowych:
od przetwarzania danych
po Ajaksa
Autor: Yuli Vasiliev
Tumaczenie: Robert Grczyski, Artur Przybya
ISBN: 978-83-246-1974-0
Tytu oryginau: PHP Oracle Web Development:
Data processing, Security, Caching, XML,
Web Services, and Ajax
Format: 170x230, stron: 392
Poznaj niezwyke moliwoci duetu OraclePHP i twrz niezawodne aplikacje!
Jak poczy PHP i Oracle w celu uzyskania optymalnej wydajnoci
i niezawodnoci?
Jak wykorzystywa funkcje XML w PHP i Oracle?
Jak poprawi wydajno dziki zastosowaniu buforowania?

Baza Danych Oracle nie ma sobie rwnych pod wzgldem wydajnoci, niezawodnoci
oraz skalowalnoci. Natomiast skryptowy jzyk PHP dziki niezwykej prostocie
stosowania stanowi jedno z najpopularniejszych narzdzi budowania aplikacji
sieciowych nawet dla niezbyt dowiadczonych programistw. Budowanie i wdraanie
aplikacji PHP opartych na Oracle pozwala wic na optymalne poczenie potnych
moliwoci i solidnoci z atwoci uycia i krtkim czasem programowania.
Ksika PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych
po Ajaksa zawiera zilustrowany praktycznymi przykadami opis technologii oraz
wszystkich narzdzi potrzebnych, aby optymalnie wykorzysta moliwoci duetu
OraclePHP. Dziki temu podrcznikowi poznasz nowe funkcje PHP i bazy danych
Oracle; dowiesz si take, na czym polega programowanie procedur skadowanych
i obsuga transakcji. Nauczysz si tworzy niezawodne aplikacje i zapewnia im wysz
wydajno dziki mechanizmom buforowania, a take uywa technologii Ajax
z technologiami Oracle Database i funkcjami PHP w celu usprawnienia reakcji aplikacji
na dziaania uytkownika.
Poczenie PHP i Oracle
Przetwarzanie danych
Tworzenie i wywoywanie wyzwalaczy
Uywanie podprogramw skadowanych
Podejcie zorientowane obiektowo
Obsuga wyjtkw
Bezpieczestwo
Buforowanie
Aplikacje oparte na XML
Usugi sieciowe
Aplikacje oparte na Ajaksie

Pocz wydajno, skalowalno i niezawodno z atwoci uycia


i krtkim czasem programowania!

Spis treci
O autorze

11

O recenzencie

13

Wprowadzenie

15

Jakie tematy zostay poruszone w ksice?


Dla kogo przeznaczona jest ta ksika?
Konwencje zastosowane w ksice
Uycie przykadowych kodw

16
17
17
18

Rozdzia 1. Rozpoczcie pracy z PHP i Oracle

19

Dlaczego PHP i Oracle?


Prostota i elastyczno
Wydajno
Niezawodno
Co zamiast PHP i Oracle?
PHP i MySQL
JSF i Oracle
Co bdzie potrzebne, aby rozpocz prac?
Wymagane komponenty oprogramowania
Rozwaania dotyczce produktu Oracle Database
Zrozumienie Oracle Database
Wybr midzy wydaniami oprogramowania Oracle Database
Pobieranie oprogramowania Oracle Database

20
20
21
21
22
22
23
23
23
25
25
25
26

Rozwaania dotyczce PHP

27

Serwer WWW Apache


Dlaczego PHP 5?
Pobieranie PHP 5

28
28
29

Zmuszenie PHP i Oracle do wsppracy


Oracle Instant Client
Zend Core for Oracle

30
30
31

Spis treci

Uywanie Oracle SQL*Plus


Dlaczego warto uywa SQL*Plus w programowaniu PHP/Oracle?
Nawizywanie poczenia z baz danych za pomoc SQL*Plus
Wykonywanie skryptw z poziomu SQL*Plus

31
31
32
34

Poczenie wszystkiego razem


Utworzenie pierwszej aplikacji PHP/Oracle
Nawizywanie poczenia z baz danych

35
37
40

Uywanie metody Local Naming


Uywanie metody Easy Connect

40
41

Wykonywanie polece SQL wzgldem bazy danych


Pobieranie i wywietlanie wynikw
Podsumowanie

Rozdzia 2. Poczenie PHP i Oracle


Przedstawienie rozszerzenia PHP OCI8
Dlaczego warto uywa rozszerzenia OCI8?
Przetwarzanie polece za pomoc rozszerzenia OCI8
Nawizywanie poczenia z Oracle za pomoc rozszerzenia OCI8
Definiowanie cigu tekstowego poczenia
Funkcje rozszerzenia OCI8, ktre su do nawizywania poczenia z Oracle
Analizowanie i wykonywanie polece SQL za pomoc rozszerzenia OCI8
Przygotowywanie polece SQL do wykonania
Uywanie zmiennych wizanych
Wykonywanie polece SQL
Obsuga bdw
Uywanie funkcji oci_error()
Uywanie funkcji trigger_error()
Uywanie wyjtkw

Pobieranie wynikw za pomoc funkcji rozszerzenia OCI8


Funkcje rozszerzenia OCI8, ktre su do pobierania wynikw
Pobieranie kolejnego rekordu
Pobranie wszystkich rekordw
Alternatywy dla rozszerzenia PHP OCI8
Uywanie PEAR DB
Uywanie ADOdb
Uywanie PDO
Tworzenie wasnej biblioteki na bazie rozszerzenia OCI8
Podsumowanie

Rozdzia 3. Przetwarzanie danych


Implementacja logiki biznesowej aplikacji PHP/Oracle
Kiedy przenosi dane do miejsca dziaania procesu przetwarzania?
Zalety przeniesienia procesu przetwarzania danych do samych danych
Sposoby implementacji logiki biznesowej wewntrz bazy danych
Wsppraca midzy komponentami implementujcymi logik biznesow

42
42
43

45
45
46
46
51
51
52
53
54
54
56
56
57
57
58

59
59
60
61
63
63
65
66
67
68

71
72
72
73
74
75

Spis treci

Uywanie skomplikowanych polece SQL


Uywanie funkcji Oracle SQL w zapytaniach

76
76

Funkcje Oracle SQL kontra przetwarzanie danych w PHP


Funkcje agregujce
Klauzula GROUP BY

77
79
80

Uywanie zcze
Wykorzystanie zalet widokw

80
83

Kluczowe korzyci pynce z uywania widokw


Ukrywanie zoonoci danych za pomoc widokw
Uywanie klauzuli WHERE

Uywanie podprogramw skadowanych


Czym s podprogramy skadowane?
Zalety podprogramw skadowanych
Przykad uycia podprogramu skadowanego
Tworzenie podprogramw skadowanych
Wywoywanie podprogramw skadowanych z poziomu PHP
Uywanie wyzwalaczy
Tworzenie wyzwalaczy
Wywoywanie wyzwalaczy
Wywoywanie procedur skadowanych z poziomu wyzwalacza
Podsumowanie

Rozdzia 4. Transakcje
Oglny opis transakcji
Czym jest transakcja?
Czym s reguy ACID?
W jaki sposb transakcje dziaaj w Oracle?
Uywanie transakcji w aplikacjach PHP/Oracle
Strukturyzacja aplikacji PHP/Oracle w celu nadzorowania transakcji
Tworzenie kodu transakcyjnego
Nadzorowanie transakcji z poziomu PHP
Przenoszenie kodu transakcyjnego do bazy danych

83
84
85

87
87
89
90
94
95
97
98
99
99
100

103
104
104
105
106
107
110
113
113
119

Uywanie wyzwalaczy
Wycofanie na poziomie polecenia

Rozwaania dotyczce izolacji transakcji


Ktr funkcj rozszerzenia OCI8 suc do nawizywania poczenia naley wybra?
Kwestie zwizane z wspbienym uaktualnianiem

119
120

123
123
127

Kwestie zwizane z nakadaniem blokad


Utracone uaktualnienia

Transakcje autonomiczne
Podsumowanie

Rozdzia 5. Podejcie zorientowane obiektowo


Implementacja klas PHP, ktre pozwalaj na wspprac z Oracle
Bloki budulcowe aplikacji

127
129

132
135

137
138
138

Tworzenie zupenie od pocztku wasnej klasy PHP


Testowanie nowo utworzonej klasy
Wykorzystanie zalet funkcji programowania zorientowanego obiektowo w PHP 5

139
141
142

Spis treci

Funkcjonalno i implementacja
Ponowne uywanie kodu
Obsuga wyjtkw
Modyfikacja istniejcej klasy w celu uycia wyjtkw
Rozrnienie midzy odmiennymi rodzajami bdw
Czy wyjtki koniecznie oznaczaj bdy?

Rozszerzanie istniejcych klas


Uywanie klas standardowych
Pakiet PEAR::Auth w dziaaniu
Zabezpieczanie stron za pomoc PEAR::Auth

Dostosowanie klas standardowych do wasnych potrzeb


Dostosowanie do wasnych potrzeb PEAR::Auth
Budowanie mniejszego kodu klienta

Oddziaywania midzy obiektami


Kompozycja
Agregacja
Komunikacja bazujca na zdarzeniach
Uywanie waciwoci obiektowych Oracle
Uywanie typw obiektowych w Oracle
Implementacja logiki biznesowej za pomoc metod obiektw Oracle
Uywanie obiektw Oracle w celu uproszczenia tworzenia aplikacji
Podsumowanie

Rozdzia 6. Bezpieczestwo
Zabezpieczanie aplikacji PHP/Oracle
Uwierzytelnianie uytkownikw
Oddzielenie zarzdzania bezpieczestwem od danych
Uywanie dwch schematw bazy danych w celu zwikszenia bezpieczestwa
Uywanie trzech schematw bazy danych w celu zwikszenia bezpieczestwa
Uywanie pakietw PL/SQL i funkcji tabelarycznych
w celu zapewnienia bezpiecznego dostpu do danych bazy danych
Uywanie atrybutu %ROWTYPE
Budowanie wasnego magazynu dla klasy PEAR::Auth
Testowanie systemu uwierzytelniania

Przeprowadzanie uwierzytelniania na podstawie tosamoci uytkownika


Uywanie sesji do przechowywania informacji o uwierzytelnionym uytkownika
Przechowywanie informacji o uytkowniku w zmiennych pakietowych
Ochrona zasobw na podstawie informacji dotyczcych uwierzytelnionego uytkownika

Uywanie skrtw
Tworzenie skrtw hase
Modyfikacja systemu uwierzytelniania
w celu przeprowadzenia operacji tworzenia skrtu
Implementacja dokadnej kontroli dostpu za pomoc widokw bazy danych
Implementacja bezpieczestwa na poziomie kolumny za pomoc widokw
Maskowanie wartoci kolumn zwracanych aplikacji
Uywanie funkcji DECODE()

Implementacja bezpieczestwa na poziomie rekordu za pomoc widokw


Bezpieczestwo na poziomie rekordu przy uyciu funkcji VPD
Podsumowanie

144
146
146
147
149
152

152
152
153
155

157
157
160

161
161
164
168
170
170
171
174
175

177
178
178
179
180
182
183
187
189
190

192
192
193
195

199
200
202
204
205
208
208

211
214
217

Spis treci

Rozdzia 7. Buforowanie
Buforowanie danych za pomoc Oracle i PHP
Buforowanie zapyta w serwerze bazy danych

219
220
220

Przetwarzanie polece SQL


Stosowanie zmiennych wizanych
w celu zwikszenia prawdopodobiestwa uycia bufora puli wspdzielonej

Uywanie kontekstu Oracle podczas buforowania

220
222

224

Tworzenie kontekstu globalnego aplikacji


Manipulowanie danymi znajdujcymi si w kontekcie globalnym
Zerowanie wartoci w kontekcie globalnym

Mechanizmy buforowania dostpne w PHP

226
228
232

236

Wybr strategii buforowania


Wywoywanie funkcji buforowania za pomoc pakietu PEAR::Cache_Lite
Uaktualnianie buforowanych danych

Implementacja buforowania bazujcego na powiadamianiu


Uywanie funkcji bazy danych powiadamiania o zmianach

236
237
240

242
244

Kontrola komunikatw powiadamiania


Budowanie procedury PL/SQL, ktra wysya powiadomienia serwerowi WWW
Przeprowadzenie krokw konfiguracyjnych wymaganych
przez mechanizm powiadamiania
Budowa uchwytu powiadamiania
Utworzenie zapytania rejestrujcego dla uchwytu powiadamiania
Szybki test

Implementacja buforowania bazujcego na powiadomieniach


za pomoc PEAR::Cache_Lite
Podsumowanie

Rozdzia 8. Aplikacje bazujce na XML-u


Przetwarzanie danych XML w aplikacjach PHP/Oracle
Przetwarzanie danych XML za pomoc PHP

244
245
246
247
249
250

251
253

255
256
256

Tworzenie danych XML za pomoc rozszerzenia PHP DOM


Wykonywanie zapyta do dokumentu DOM za pomoc XPath
Transformacja i przetwarzanie danych XML za pomoc XSLT

Wykonywanie przetwarzania danych XML wewntrz bazy danych

257
259
260

265

Uywanie funkcji generowania SQL/XML w Oracle


Przeniesienie caego procesu przetwarzania danych XML do bazy danych
Przechowywanie danych XML w bazie danych
Przeprowadzanie transformacji XSLT wewntrz bazy danych

Budowanie aplikacji PHP na podstawie Oracle XML DB


Uywanie bazy danych Oracle do przechowywania,
modyfikowania i pobierania danych XML

265
268
269
271

272
273

Dostpne opcje przechowywania danych XML w bazie danych Oracle


Uywanie XMLType do obsugi danych XML w bazie danych
Uywanie schematw XML
Pobieranie danych XML

Uzyskanie dostpu do danych relacyjnych za pomoc widokw XMLType

273
275
277
281

285

Uywanie widokw XMLType


Tworzenie widokw XMLType bazujcych na schemacie XML
Przeprowadzanie operacji DML w widoku XMLType bazujcym na schemacie XML

285
286
289

Spis treci

Uywanie repozytorium Oracle XML DB


Manipulowanie zasobami repozytorium za pomoc kodu PL/SQL
Uzyskanie dostpu do zasobw repozytorium za pomoc SQL
Wykorzystanie zalet standardowych protokow internetowych

Obsuga transakcji
Pobieranie danych za pomoc Oracle XQuery
Uywanie silnika XQuery do budowania danych XML
na podstawie danych relacyjnych
Rozoenie danych XML na posta danych relacyjnych
Podsumowanie

Rozdzia 9. Usugi sieciowe


Udostpnienie aplikacji PHP/Oracle jako usugi sieciowej za pomoc rozszerzenia PHP SOAP
Komunikacja za pomoc SOAP
Co jest wymagane do zbudowania usugi sieciowej SOAP?
Budowanie usugi sieciowej SOAP na podstawie aplikacji PHP/Oracle
Budowanie logiki biznesowej usugi sieciowej wewntrz bazy danych
Tworzenie schematu XML przeznaczonego do weryfikacji nadchodzcych dokumentw
Generowanie unikalnych identyfikatorw dla przekazywanych dokumentw
Tworzenie podprogramw PL/SQL implementujcych logik biznesow usugi sieciowej

Budowanie uchwytu klasy PHP


Uywanie WSDL
Tworzenie serwera SOAP za pomoc rozszerzenia PHP SOAP
Budowanie klienta SOAP w celu przetestowania serwera SOAP
Bezpieczestwo
Implementacja logiki autoryzacji wewntrz bazy danych
Tworzenie uchwytu klasy PHP
Tworzenie dokumentu WSDL
Tworzenie skryptu klienta
Podsumowanie

Rozdzia 10. Aplikacje oparte na Ajaksie


Budowanie aplikacji PHP/Oracle opartych na Ajaksie
Ajax zasada dziaania
Projekt aplikacji monitorujcej opartej na Ajaksie/PHP/Oracle
Rozwizanie oparte na Ajaksie
Tworzenie struktur danych
Tworzenie skryptu PHP przetwarzajcego dania Ajaksa
Uywanie obiektu JavaScript XMLHttpRequest
Zoenie aplikacji w cao
Uycie pamici podrcznej w celu zwikszenia szybkoci pracy aplikacji

Implementacja rozwiza Master/Detail z uyciem metodologii Ajax


Projektowanie rozwizania Master/Detail wykorzystujcego Ajaksa
Opis dziaania przykadowej aplikacji
Tworzenie struktur danych
Generowanie kodu HTML za pomoc Oracle XQuery
Wysyanie da POST za pomoc Ajaksa
Tworzenie stylw CSS
Zoenie aplikacji w cao

Podsumowanie

293
294
294
295

297
298
299
301
302

303
304
304
305
307
308
308
311
313

317
319
322
323
326
327
329
330
332
333

335
336
336
337
339
339
340
341
345
347

348
348
349

351
353
354
356
357

358

Spis treci

Dodatek A Instalacja oprogramowania PHP i Oracle


Instalacja oprogramowania Oracle Database
Instalacja wyda Oracle Database Enterprise/Standard
Instalacja wydania Oracle Database Express Edition

359
360
360
363

Instalacja wydania Oracle Database XE w systemie Windows


Instalacja wydania Oracle Database XE w systemie Linux

Instalacja serwera WWW Apache


Instalacja PHP
Instalacja PHP w systemie Windows
Instalacja PHP w systemie z rodziny Unix
Testowanie PHP
Zbudowanie mostu midzy Oracle i PHP
Biblioteki Oracle Instant Client
Wczenie rozszerzenia OCI8 w istniejcej instalacji PHP
Instalacja narzdzia SQL*Plus Instant Client
Instalacja Zend Core for Oracle
Instalacja Zend Core for Oracle w systemie Windows
Instalacja Zend Core for Oracle w systemie Linux

Skorowidz

363
365

365
367
367
368
369
369
369
371
372
373
373
374

375

4
Transakcje
Aby uzyska pewno, e uywane dane zawsze bd prawidowe, naley stosowa transakcje.
W skrcie: dostarczaj one mechanizm pozwalajcy na bezpieczne modyfikowanie danych przechowywanych w bazie danych poprzez przeniesienie bazy danych z jednego spjnego stanu
do kolejnego.
Klasycznym przykadem wykorzystania transakcji jest operacja bankowa, taka jak przelew
rodkw pieninych z jednego konta bankowego na inne. Zamy, e zachodzi potrzeba
przelania rodkw pieninych z konta oszczdnociowego na konto biece. W celu wykonania tej operacji trzeba bdzie przeprowadzi przynajmniej dwa kroki: zmniejszy wartoci
rodkw na koncie oszczdnociowym i zwikszy warto rodkw na koncie biecym.
Oczywiste jest, e w tego rodzaju sytuacji konieczne bdzie potraktowanie obu operacji jako
pojedynczej, aby zachowa saldo midzy kontami. Dlatego te adna z wymienionych operacji nie
moe zosta przeprowadzona oddzielnie musz by zakoczone obie lub adna z nich
programista musi zagwarantowa, e albo obie operacje zakocz si powodzeniem, albo
adna z nich nie bdzie przeprowadzona. W takiej sytuacji doskonaym rozwizaniem jest zastosowanie transakcji.
W rozdziale zostay omwione rne mechanizmy, ktre mog by uyte do przeprowadzania
transakcji za pomoc technologii PHP i Oracle. Zaczniemy od oglnego omwienia transakcji,
poniewa te informacje s bardzo wane w celu dokadnego zrozumienia sposobu dziaania
transakcji. Nastpnie zostay przedstawione szczegowy dotyczce stosowania na rne sposoby transakcji w aplikacjach PHP/Oracle.

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

Oglny opis transakcji


Przed rozpoczciem budowania wasnych aplikacji PHP/Oracle wykorzystujcych transakcje
naley zapozna si z podstawowymi informacjami, ktre dotycz transakcji, i przekona si,
jak mog by przeprowadzane z poziomu PHP i Oracle. W podrozdziale zaprezentowano
oglny opis transakcji oraz poruszono nastpujce zagadnienia:
Q Czym s transakcje i kiedy programista moe chcie je stosowa?
Q Jak przeprowadza transakcje za pomoc PHP i Oracle?
Q Jak zorganizowa aplikacj PHP/Oracle, aby efektywnie kontrolowa transakcje?
Poniewa wymienione powyej zagadnienia najlepiej mona zrozumie za pomoc przykadw, w podrozdziale znajdzie si kilka prostych przykadw pokazujcych moliwy sposb
wykorzystania transakcji w aplikacjach PHP/Oracle.

Czym jest transakcja?


Oglnie rzecz biorc, transakcja jest czynnoci lub seri czynnoci, ktre przenosz system
z jednego stanu spjnoci do kolejnego. Z punktu widzenia programisty budujcego aplikacje
oparte na bazie danych transakcja moe by uznawana za niewidzialny zestaw operacji, ktre
przenosz baz danych z jednego stanu spjnoci do kolejnego.
Transakcja jest jednostk logiczn pracy, zawierajc jedno lub wiksz liczb polece SQL, ktre mog
by w caoci albo zatwierdzone, albo wycofane.

Oznacza to, e wszystkie polecenia SQL zawarte w transakcji musz by z powodzeniem zakoczone, aby caa transakcja moga zosta zatwierdzona, dziki czemu zmiany przeprowadzone przez wszystkie operacje DML zostaj trwale przeprowadzone. Graficznie zostao to
pokazane na rysunku 4.1.

Rysunek 4.1. Graficzne przedstawienie sposobu dziaania transakcji

104

Rozdzia 4. Transakcje

Jak mona zobaczy na powyszym rysunku, polecenia SQL skadajce si na transakcj przenosz dane, na ktrych operuj z jednego stanu spjnoci do kolejnego. Transakcja musi zosta
zatwierdzona, aby wprowadzone przez ni zmiany zostay zastosowane w bazie danych i tym
samym przeniosy dane do kolejnego stanu spjnoci. W przeciwnym razie wszystkie polecenia SQL wykonane przez transakcj zostan wycofane, a dane pozostan w stanie, w ktrym
znajdoway si w chwili rozpoczcia transakcji.
Jeeli w trakcie wykonywania transakcji wystpi bd serwera, na przykad awaria sprztu
komputerowego, efekty transakcji zostan automatycznie wycofane. Jednak w pewnych sytuacjach programista moe chcie rcznie wycofa ukoczon (ale jeszcze nie zatwierdzon)
transakcj, w zalenoci od ustalonego warunku. Taka sytuacja zostaa pokazana graficznie na
rysunku 4.2.

Rysunek 4.2. Graficzne przedstawienie warunkowego zatwierdzenia transakcji

Jak wida na powyszym rysunku, po zakoczeniu wykonywania wszystkich polece transakcji programista ma moliwo albo jej zatwierdzenia, albo wycofania.

Czym s reguy ACID?


ACID to akronim oznaczajcy Atomicity (niepodzielno), Consistency (spjno), Isolation
(izolacja) oraz Durability (trwao). Kady system zarzdzania baz danych obsugujcy transakcje
musi spenia powysze cechy charakterystyczne. Ich podsumowanie znalazo si w pierwszej
tabeli na nastpnej stronie.
Baza danych Oracle obsuguje wszystkie waciwoci ACID wymienione w powyszej tabeli.
Dlatego podczas budowania aplikacji transakcyjnych na Oracle nie trzeba projektowa wasnych schematw gwarantujcych spjno i integralno danych. Zamiast tego zawsze lepszym rozwizaniem bdzie wykorzystanie transakcji Oracle i zrzucenie obsugi tego rodzaju
problemw na baz danych.
105

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

Waciwo

Opis

Niepodzielno

Transakcja stanowi niepodzieln jednostk pracy. Oznacza to, e albo wszystkie operacje
w ramach transakcji zostan wykonane, albo nie bdzie wykonana adna z nich.

Spjno

Transakcja przenosi baz danych z jednego stanu spjnoci do kolejnego. Oznacza to,
e podczas przeprowadzania transakcji nie mog by zamane adne czynniki wpywajce
na spjno bazy danych. Jeeli transakcja zamie jakiekolwiek reguy spjnoci,
zostanie wycofana.

Izolacja

Do chwili zatwierdzenia transakcji zmiany wprowadzane przez operacje skadajce si


na transakcj nie powinny by widoczne dla innych, rwnoczenie przeprowadzanych
transakcji.

Trwao

Gdy transakcja zostanie zatwierdzona, wszystkie modyfikacje wprowadzone przez


transakcj stan si trwae i widoczne dla innych transakcji. Trwao gwarantuje,
e jeli zatwierdzenie transakcji zakoczy si powodzeniem, w przypadku awarii
systemu nie bd one wycofane.

W jaki sposb transakcje dziaaj w Oracle?


W podrozdziale zostanie pokrtce przedstawiony oglny opis dziaania transakcji w Oracle.
Szczegowe informacje dotyczce sposobu dziaania transakcji w bazie danych Oracle mona
znale w dokumentacji Oracle: w rozdziale Transaction Management w podrczniku uytkownika Oracle Database Concepts.
W Oracle transakcja nie rozpoczyna si jawnie, lecz niejawnie podczas uruchamiania pierwszego wykonywalnego polecenia SQL. Jednak istnieje kilka sytuacji powodujcych zakoczenie transakcji. Przedstawiono w poniszej tabeli:
Sytuacja

Opis

Wydanie
polecenia COMMIT

Po wydaniu polecenia COMMIT nastpuje zakoczenie wykonywania biecej transakcji.


Polecenie powoduje, e zmiany wprowadzone przez polecenia SQL transakcji staj si
trwae.

Wydanie
polecenia ROLLBACK

Po wydaniu polecenia ROLLBACK nastpuje zakoczenie wykonywania biecej


transakcji. Polecenie to powoduje, e zmiany wprowadzone przez polecenia SQL
transakcji zostaj wycofane.

Wydanie
polecenia DDL

Jeeli zostanie wydane polecenie DDL, Oracle w pierwszej kolejnoci zatwierdzi biec
transakcj, a nastpnie wykona i zatwierdzi polecenie DDL w nowej transakcji, ktra
skada si z pojedynczego polecenia.

Zamknicie
poczenia

Kiedy poczenie zostanie zamknite, Oracle automatycznie zatwierdzi biec


transakcj w tym poczeniu.

Nieprawidowe
przerwanie
wykonywania
programu

Jeeli wykonywanie programu zostanie nieprawidowo przerwane, Oracle


automatycznie wycofa biec transakcj.

106

Rozdzia 4. Transakcje

Jak mona si przekona na podstawie powyszej tabeli, transakcja zawsze bdzie albo zatwierdzona, albo wycofana, niezalenie od tego, czy zostanie wyranie zatwierdzona, czy wycofana.
Warto jednak zwrci uwag, e zawsze dobr praktyk jest wyrane zatwierdzanie lub wycofywanie transakcji zamiast polegania na zachowaniu domylnym Oracle. W rzeczywistoci
zachowanie domylne aplikacji transakcyjnej moe by rne w zalenoci od narzdzia stosowanego przez aplikacj do nawizywania poczenia z baz danych Oracle.
Na przykad jeeli skrypt PHP wsppracuje z baz danych Oracle za pomoc rozszerzenia
OCI8, nie mona liczy na to, e aktywna transakcja w poczeniu zostanie automatycznie
zatwierdzona po zamkniciu tego poczenia. W takim przypadku po zamkniciu poczenia
lub zakoczeniu wykonywania skryptu aktywna transakcja zostanie wycofana.
Natomiast jeeli rozczenie z baz danych nastpi po wydaniu polecenia DISCONNECT z poziomu
narzdzia SQL*Plus lub nastpi poczenie z baz jako inny uytkownik uywajcy polecenia
CONNECT bd sesja SQL*Plus zostanie zamknita w wyniku wydania polecenia EXIT, aktywna
transakcja w poczeniu bdzie zatwierdzona.
Aby unikn nieoczekiwanego zachowania w aplikacji, zawsze dobrze jest wyranie zatwierdza bd
wycofywa transakcje, zamiast polega na zachowaniu domylnym aplikacji transakcyjnej.

Uywanie transakcji w aplikacjach PHP/Oracle


Jak wspomniano w poprzednim podrozdziale, w Oracle mona wyranie albo zatwierdzi, albo
wycofa transakcj, uywajc polecenia odpowiednio COMMIT lub ROLLBACK. W celu wykonania powyszych polece z poziomu kodu PHP nie trzeba uywa funkcji oci_parse() i oci_execute(),
jak podczas wykonywania innych polece SQL, takich jak SELECT lub INSERT. Zamiast tego
uywa si funkcji rozszerzenia OCI8 o nazwach oci_commit() i oci_rollback().
Przedstawiony poniej skrypt PHP demonstruje sposb wyranego zatwierdzenia lub wycofania transakcji z poziomu kodu PHP podczas uywania operacji DML. Zadaniem skryptu
jest prba uaktualnienia rekordw tabeli employees, reprezentujcych pracownikw, ktrych
identyfikator stanowiska wynosi ST_MAN (meneder magazynu). Uaktualnienie polega na
zwikszeniu wysokoci pensji o 10%. Jeeli uaktualnienie jednego lub wikszej liczby rekordw
zakoczy si niepowodzeniem, caa transakcja zostanie wycofana, a uaktualnionym polom
pensji bd przywrcone ich wartoci pocztkowe. Cay proces podsumowuj ponisze kroki:
Q Krok 1.: wykonanie zapytania wzgldem tabeli employees w celu uzyskania liczby
rekordw przedstawiajcych pracownikw na wskazanym stanowisku (menederw
magazynu).
Q Krok 2.: rozpoczcie transakcji i wykonanie operacji UPDATE wzgldem tabeli
employees w celu przeprowadzenia prby zwikszenia pensji menederw
magazynu o 10%.

107

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

Q Krok 3.: wycofanie transakcji, jeli liczba rekordw zmodyfikowanych przez


operacj UPDATE bdzie mniejsza ni liczba rekordw przedstawiajcych

menederw. W przeciwnym razie transakcja zostanie zatwierdzona.


Teraz warto zapozna si z kodem rdowym skryptu, aby przekona si, jak powysze kroki
mog by zaimplementowane w PHP za pomoc funkcji rozszerzenia OCI8.
<?php
// Plik: trans.php.
if(!$dbConn = oci_connect('hr', 'hr', '//localhost/orcl')) {
$err = oci_error();
trigger_error('Nie mona nawiza poczenia z baz danych: '
. $err['message'], E_USER_ERROR);
};
$query = "SELECT count(*) num_rows FROM employees
WHERE job_id='ST_MAN'";
$stmt = oci_parse($dbConn,$query);
if (!oci_execute($stmt)) {
$err = oci_error($stmt);
trigger_error('Wykonanie zapytania zakoczyo si niepowodzeniem: '
. $err['message'], E_USER_ERROR);
};
oci_fetch($stmt);
$numrows = oci_result($stmt, 'NUM_ROWS');
oci_free_statement($stmt);
$query = "UPDATE employees e
SET salary = salary*1.1
WHERE e.job_id='ST_MAN' AND salary*1.1
BETWEEN (SELECT min_salary FROM jobs j WHERE j.job_id=e.job_id)
AND (SELECT max_salary FROM jobs j WHERE j.job_id=e.job_id)";
$stmt = oci_parse($dbConn,$query);
if (!oci_execute($stmt, OCI_DEFAULT)) {
$err = oci_error($stmt);
trigger_error('Operacja uaktualnienia zakoczya si niepowodzeniem: '
. $err['message'], E_USER_ERROR);
}
$updrows = oci_num_rows($stmt);
print "Prba uaktualnienia ".$numrows." rekordw.<br />";
print "Udao si uaktualni ".$updrows." rekordw.<br />";
if ($updrows<$numrows) {
if (!oci_rollback($dbConn)) {
$err = oci_error($dbConn);
trigger_error('Nie udao si wycofa transakcji: '
.$err['message'], E_USER_ERROR);
}
print "Transakcja zostaa wycofana.";
} else {
if (!oci_commit($dbConn)) {
$err = oci_error($dbConn);

108

Rozdzia 4. Transakcje

trigger_error('Nie udao si zatwierdzi transakcji: '


.$err['message'], E_USER_ERROR);
}
print "Transakcja zostaa zatwierdzona.";
}
?>

W powyszym skrypcie zdefiniowano zapytanie zwracajce liczb rekordw, ktre przedstawiaj pracownikw zatrudnionych jako menederowie magazynu. W zapytaniu uyto funkcji
count() w celu obliczenia liczby rekordw speniajcych kryteria zdefiniowane w klauzuli
WHERE zapytania. W omawianym przypadku wartoci zwrotn funkcji count(*) jest liczba rekordw reprezentujcych pracownikw, dla ktrych warto pola job_id wynosi ST_MAN.
W skrypcie liczba rekordw przedstawiajcych menederw magazynu jest pobierana z bufora wynikowego za pomoc poczenia funkcji oci_fetch() i oci_result(). Nie trzeba w tym
przypadku stosowa ptli, poniewa zapytanie zwraca tylko jeden rekord zawierajcy pojedyncze pole o nazwie num_rows.
Nastpnie wykonywane jest zapytanie uaktualniajce kolumn salary tabeli employees. Uaktualnienie polega na zwikszeniu pensji menederw magazynu o 10%. Zapytanie uaktualnia
wysoko pensji tylko wtedy, gdy nowa wysoko pensji bdzie miecia si midzy minimaln i maksymaln wysokoci pensji ustalonymi dla menederw magazynu i zdefiniowanymi
w tabeli jobs.
W omawianym przykadzie polecenie UPDATE jest wykonywane w trybie wykonywania OCI_
DEFAULT. W ten sposb nastpuje rozpoczcie transakcji, ktra pozwala programicie w dalszej
czci skryptu na wyrane zatwierdzenie lub wycofanie zmian wprowadzonych przez polecenie UPDATE. Interesujc kwesti, na ktr warto zwrci uwag, jest fakt, e domylny tryb
wykonywania to OCI_COMMIT_ON_SUCCESS, w ktrym polecenie jest zatwierdzane automatycznie, jeli jego wykonywanie zakoczy si powodzeniem.
Wedug dokumentacji Oracle aplikacja zawsze powinna wyranie zatwierdza bd wycofywa transakcj przed zakoczeniem dziaania programu. Jednak podczas uywania rozszerzenia PHP OCI8 nie trzeba
tego robi, gdy polecenia SQL s wykonywane w trybie OCI_COMMIT_ON_SUCCESS. W wymienionym
trybie polecenie SQL jest zatwierdzane automatycznie, jeli jego wykonanie zakoczy si powodzeniem
(czyli w sytuacji podobnej do wyranego zatwierdzenia natychmiast po wykonaniu polecenia). Jeeli
bd serwera uniemoliwi zakoczenie powodzeniem wykonywania polecenia SQL, Oracle automatycznie
wycofa wszystkie zmiany wprowadzone przez nie.

W omawianym skrypcie funkcja oci_num_rows() jest wywoywana w celu uzyskania liczby rekordw zmodyfikowanych przez operacj UPDATE. Po poznaniu liczby rekordw przedstawiajcych menederw magazynu oraz liczby faktycznie uaktualnionych mona porwna te
wartoci i sprawdzi, czy s identyczne.

109

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

W powyszym skrypcie wycofanie transakcji nastpuje, gdy liczba uaktualnionych rekordw


jest mniejsza ni cakowita liczba rekordw przedstawiajcych menederw magazynu. Ma to
sens, poniewa niedopuszczalna jest sytuacja, w ktrej uaktualnione zostan rekordy tylko
niektrych menederw magazynu.
Moliwo wycofania zmian w przypadku wystpienia takiej sytuacji ma znaczenie krytyczne
pozwala wwczas na uycie innego skryptu, ktry bdzie mg prawidowo uaktualni
wszystkie rekordy przedstawiajce menederw magazynu. Na przykad w rzeczywistej sytuacji prawdopodobnie podanym rozwizaniem bdzie zwikszenie pensji menedera magazynu do maksymalnej dopuszczalnej wysokoci, jeli jej podwyka o 10% przekroczy to dozwolone maksimum.
Jeeli operacja UPDATE zmodyfikuje wszystkie rekordy przedstawiajce menederw magazynu, transakcj mona zatwierdzi za pomoc funkcji oci_commit(), dziki czemu wprowadzone zmiany bd trwae.
Innym elementem, na ktry warto zwrci uwag w omawianym skrypcie, jest uyty mechanizm obsugi bdw. Jeeli w trakcie wykonywania funkcji oci_rollback() lub oci_commit()
wystpi bd, identyfikator poczenia bdzie przekazany funkcji oci_error(), ktra z kolei
zwrci komunikat bdu opisujcy powstay bd.

Strukturyzacja aplikacji PHP/Oracle


w celu nadzorowania transakcji
Jak Czytelnik moe przypomnie sobie z lektury rozdziau 3., oglnie rzecz biorc, dobrym
pomysem jest umieszczenie wewntrz bazy danych kluczowej logiki biznesowej aplikacji
PHP/Oracle. Pado tam te rwnie stwierdzenie, e w prostych przypadkach nie trzeba nawet tworzy kodu PL/SQL w celu przeniesienia do bazy danych procesu przetwarzania danych. Zamiast tego mona zaprojektowa skomplikowane zapytania SQL, ktre po wydaniu
bd nakazyway serwerowi bazy danych przeprowadzenie wszystkich wymaganych operacji
przetwarzania danych.
Wracajc do przykadu omwionego w poprzednim podrozdziale: istnieje moliwo modyfikacji uytego w nim polecenia UPDATE w taki sposb, aby rekordy przedstawiajce menederw magazynu byy uaktualniane tylko wtedy, gdy nowa wysoko pensji kadego menedera
nadal bdzie znajdowaa si midzy wartoci minimaln i maksymaln dla tego stanowiska.
Wymienione wartoci s zdefiniowane w tabeli jobs. Taka modyfikacja wyeliminuje potrzeb
wykonywania oddzielnego zapytania, ktre zwraca liczb rekordw speniajcych powyszy
warunek. W ten sposb nastpi zmniejszenie iloci kodu koniecznego do napisania w celu
implementacji danego zachowania funkcji.
W skrcie: nowa wersja polecenia UPDATE czy w ramach pojedynczego polecenia wszystkie
trzy kroki wymienione na pocztku poprzedniego podrozdziau. Nie trzeba nawet wyranie

110

Rozdzia 4. Transakcje

zatwierdza bd wycofywa operacji UPDATE. Zamiast tego polecenie UPDATE mona wyda
w trybie OCI_COMMIT_ON_SUCCESS, ktry gwarantuje, e operacja zostanie automatycznie zatwierdzona, jeli jej wykonanie zakoczy si powodzeniem, a w przeciwnym razie wycofana.
Przedstawiony poniej skrypt prezentuje w dziaaniu now wersj polecenia UPDATE:
<?php
// Plik: transQuery.php.
if(!$dbConn = oci_connect('hr', 'hr', '//localhost/orcl')) {
$err = oci_error();
trigger_error('Nie mona nawiza poczenia z baz danych: '
. $err['message'], E_USER_ERROR);
};
$jobno = 'ST_MAN';
$query = "
UPDATE (SELECT salary, job_id FROM employees WHERE
(SELECT count(*) FROM employees WHERE job_id=:jobid AND
salary*1.1 BETWEEN (SELECT min_salary FROM jobs WHERE
job_id=:jobid) AND
(SELECT max_salary FROM jobs WHERE
job_id=:jobid)) IN
(SELECT count(*) FROM employees WHERE job_id=:jobid)
) emp
SET emp.salary = salary*1.1
WHERE emp.job_id=:jobid";
$stmt = oci_parse($dbConn,$query);
oci_bind_by_name($stmt, ':jobid', $jobno);
if (!oci_execute($stmt, OCI_COMMIT_ON_SUCCESS)) {
$err = oci_error($stmt);
trigger_error('Wykonanie zapytania zakoczyo si niepowodzeniem: '
. $err['message'], E_USER_ERROR);
};
$updrows = oci_num_rows($stmt);
if ($updrows>0) {
print "Transakcja zostaa zatwierdzona.";
} else {
print "Transakcja zostaa wycofana.";
}
?>

W powyszym fragmencie kodu zdefiniowano polecenie UPDATE, ktre spowoduje uaktualnienie wszystkich rekordw reprezentujcych menederw magazynu poprzez zwikszenie wysokoci ich pensji o 10%, pod warunkiem e adna z nowych wartoci pensji nie przekroczy
maksymalnej pensji menedera magazynu zdefiniowanej w tabeli jobs. Jeeli chocia jedna
pensja przekroczy warto maksymaln, polecenie UPDATE nie uaktualni adnych rekordw.
Aby uzyska taki sposb dziaania, zamiast podawania tabeli employees w klauzuli polecenia
UPDATE uyte zostao polecenie SELECT, ktrego wartoci zwrotn s albo wszystkie rekordy

111

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

tabeli employees, albo aden z nich. Zaley to od tego, czy wszystkie rekordy speniajce warunek zdefiniowany w klauzuli WHERE polecenia UPDATE (w omawianym przypadku bd to
wszystkie rekordy reprezentujce menederw magazynu) mog by uaktualnione w taki sposb, aby kada nowa wysoko pensji nie przekraczaa wartoci maksymalnej pensji dla tego
stanowiska.
To polecenie SELECT jest uznawane za widok wewntrzny. W przeciwiestwie do zwykych widokw
omwionych w podrozdziale Wykorzystanie zalet widokw, znajdujcym si w rozdziale 3., widoki
wewntrzne nie s obiektami schematu bazy danych, ale podzapytaniami, ktre mog by stosowane
jedynie w ramach zawierajcych je polece za pomoc aliasw.

W omawianym przykadzie zastosowanie w poleceniu UPDATE wewntrznego widoku emp powoduje wyeliminowanie potrzeby wykonywania oddzielnego zapytania zwracajcego liczb
rekordw reprezentujcych menederw magazynu, a nastpnie sprawdzajcego, czy otrzymana liczba jest rwna liczbie rekordw faktycznie zmodyfikowanych przez polecenie UPDATE.
Teraz skrypt wykonuje tylko pojedyncze zapytanie SQL, dziki czemu wyranie skraca czas
wykonywania skryptu.
Omwiony skrypt jest dobrym przykadem pokazujcym korzyci, jakie mona odnie po przeniesieniu
kluczowej logiki biznesowej aplikacji PHP/Oracle z PHP do bazy danych Oracle. Tu zamiast uywania
dwch oddzielnych polece i analizowania ich wynikw w PHP zastosowane zostao tylko jedno polecenie SQL, ktre powoduje, e przetwarzanie danych zachodzi cakowicie w serwerze bazy danych.

Warto take zwrci uwag na uyty w skrypcie sposb wizania zmiennych. Zmienna PHP
jobno jest dowizywana do znacznika jobid uytego w poleceniu UPDATE. Interesujcy jest fakt, e
znacznik zmiennej wizanej jobid pojawia si w poleceniu czciej ni tylko jednokrotnie.
Inaczej ni w poprzednim przykadzie, w ktrym polecenie UPDATE byo wykonywane w trybie OCI_DEFAULT, wyranie rozpoczynajcym transakcj, nowa wersja skryptu wykonuje polecenie w trybie OCI_COMMIT_ON_SUCCESS. Operacja UPDATE jest wic automatycznie zatwierdzana, jeli jej wykonanie zakoczy si powodzeniem.
Jak wczeniej wspomniano, OCI_COMMIT_ON_SUCCESS jest trybem domylnym wykonywania polecenia. Oznacza to, e nie trzeba wyranie go okrela podczas wywoywania funkcji oci_execute().
W omawianym przykadzie zosta wyranie umieszczony w kodzie rdowym, aby zwrci na to uwag.

W poprzednim przykadzie nadal uywano funkcji oci_num_rows() w celu pobrania liczby rekordw zmodyfikowanych przez polecenie UPDATE. Jednak tym razem nie trzeba porwnywa
tej liczby z cakowit liczb rekordw reprezentujcych menederw magazynu, jak to miao
miejsce w przypadku poprzedniego skryptu. Wszystko, co trzeba zrobi, to prostu sprawdzi,
czy liczba rekordw zmodyfikowanych przez polecenie UPDATE jest wiksza ni 0.
112

Rozdzia 4. Transakcje

Jeeli liczba uaktualnionych rekordw jest wiksza ni 0, oznacza to, e operacja UPDATE zmodyfikowaa wszystkie rekordy reprezentujce menederw magazynu i zostaa z powodzeniem zatwierdzona. W takim przypadku naley wywietli uytkownikowi komunikat informujcy o zatwierdzeniu transakcji.
Jeeli liczba uaktualnionych rekordw wynosi 0, oznacza to, e operacja UPDATE nie zmodyfikowaa adnych rekordw. W takim przypadku naley wywietli uytkownikowi komunikat
informujcy o wycofaniu transakcji. Jednak w rzeczywistoci transakcja jest zatwierdzona, ale
aden rekord nie zosta zmodyfikowany przez operacj UPDATE.

Tworzenie kodu transakcyjnego


Dotychczas przedstawiono kilka prostych przykadw pokazujcych podstawy dziaania
transakcji Oracle z PHP. W podrozdziale zostan zaprezentowane bardziej skomplikowane
przykady stosowania transakcji w aplikacjach PHP/Oracle.

Nadzorowanie transakcji z poziomu PHP


Jak Czytelnik dowiedzia si z przykadw omwionych we wczeniejszej czci rozdziau,
funkcja oci_execute() pozwala na wykonywanie polecenia SQL w dwch trybach OCI_COMMIT_
ON_SUCCESS oraz OCI_DEFAULT.
Podczas gdy stosowanie trybu OCI_COMMIT_ON_SUCCESS powoduje, e polecenia s automatycznie zatwierdzane, uycie trybu OCI_DEFAULT wymaga wyranego wywoania funkcji oci_commit()
w celu zatwierdzenia transakcji lub oci_rollback(), aby j wycofa.
Jednak warto zwrci uwag, e gdy polecenie jest wykonywane w trybie OCI_DEFAULT, utworzona wwczas transakcja nadal moe by zatwierdzona bez wywoywania funkcji oci_commit().
W tym celu pniejsze polecenie naley wykona w trybie OCI_COMMIT_ON_SUCCESS.
Powysza technika moe by zastosowana podczas grupowania dwch lub wikszej liczby
polece w pojedyncz transakcj. Aby zagwarantowa, e caa transakcja bdzie wycofana,
kiedy wykonanie jednego z polece zakoczy si niepowodzeniem lub zostan uzyskane wyniki wskazujce na konieczno wycofania transakcji, mona po prostu przerwa wykonywanie skryptu. W tym celu mona wywoa na przykad funkcj trigger_error() wraz ze sta
E_USER_ERROR jako drugim parametrem, a tym samym wycofa transakcj bez potrzeby wywoywania funkcji oci_rollback().
Czytelnik moe si zastanawia, dlaczego omawiany jest niejawny sposb koczenia transakcji
Oracle z poziomu PHP zamiast wyranego wywoania funkcji oci_commit() bd oci_rollback().
W kocu druga z wymienionych funkcji stanowi zalecan metod koczenia transakcji. Oglnie

113

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

rzecz biorc, celem tej analizy jest umoliwienie atwiejszego zrozumienia sposobu dziaania
transakcji Oracle w skryptach PHP, ktre wspdziaaj z baz danych za pomoc rozszerzenia OCI8.
W przykadzie, ktry zostanie omwiony poniej, uyto struktur danych, ktre zdefiniowano
w podrozdziale Przykad uycia podprogramu skadowanego, znajdujcym si w rozdziale 3.
Zanim jednak przejdziemy do przykadu, konieczne jest zmodyfikowanie wymienionych struktur
danych w przedstawiony poniej sposb. Te polecenia SQL mona wykona z poziomu narzdzia SQL*Plus po nawizaniu poczenia z baz danych jako usr/usr:
ALTER TABLE accounts
ADD (num_logons INT);
UPDATE accounts
SET num_logons = 0;
COMMIT;
DELETE logons;
ALTER TABLE logons
ADD CONSTRAINT log_time_day
CHECK (RTRIM(TO_CHAR(log_time, 'Day'))
NOT IN ('Saturday', 'Sunday'));

Wydanie polecenia ALTER TABLE w powyszym bloku kodu powoduje dodanie do tabeli accounts
kolumny num_logons typu INT. W nowej kolumnie bdzie przechowywana liczba udanych operacji
logowania kadego uytkownika. W tym celu gdy uwierzytelnienie uytkownika zakoczy si
powodzeniem, trzeba bdzie zwikszy liczb operacji logowania przechowywan w polu
num_logons.
Oczywicie, nadal mona si obej bez tej kolumny, wydajc wzgldem tabeli logons zapytanie podobne do poniszego:
SELECT count(*) FROM logons WHERE usr_id='bob';

Jednak wraz ze wzrostem liczby operacji logowania powysze zapytanie bdzie bardzo kosztowne jak na otrzymanie informacji o liczbie logowa przeprowadzonych przez danego uytkownika.
Po dodaniu komuny num_logons do tabeli accounts nowej kolumnie naley ustawi warto
pocztkow wynoszc 0. Ewentualnie wczeniejsze polecenie ALTER TABLE mona byo wyda
z uyciem klauzuli DEFAULT wzgldem kolumny num_logons, na przykad nastpujco:
ALTER TABLE accounts
ADD (num_logons INT DEFAULT 0);

W omawianym bloku kodu nastpuje wyrane zatwierdzenie transakcji, aby zmiany wprowadzone przez operacj UPDATE byy trwae.
W kolejnym kroku usuwane s wszystkie rekordy tabeli logons. Ten krok jest wymagany, aby
zagwarantowa prawidowe wykonanie polecenia check constraint zdefiniowanego w nastpnym

114

Rozdzia 4. Transakcje

kroku. W omawianym przykadzie mona pomin ten krok, jeeli tabela logons nie zawiera
rekordw utworzonych w sobot lub niedziel, co umoliwi prawidowe wykonanie polecenia
check constraint zdefiniowanego w kolejnym kroku. W przeciwnym razie podczas prby wykonania polecenia ALTER TABLE zostanie wywietlony nastpujcy komunikat bdu:
ERROR at line 2:
ORA-02293: cannot validate (USR.LOG_TIME_DAY) - check constraint violated

W skrypcie definicja check constraint obejmuje kolumn log_time tabeli logons. Wymienione ograniczenie uniemoliwia wstawianie nowych rekordw do tabeli logons w sobot lub
niedziel. Pozwala to na modyfikacj systemu uwierzytelniania w taki sposb, aby uniemoliwi uytkownikom logowanie si w soboty i niedziele, a tym samym pozwoli na logowanie
jedynie w dni robocze. W pniejszym czasie takie ograniczenie zawsze bdzie mona usun
poprzez wydanie nastpujcego polecenia:
ALTER TABLE logons DROP CONSTRAINT log_time_day;

Wrmy jeszcze do polecenia ALTER TABLE, ktre przedstawiono powyej. Warto zwrci
uwag na uyty format 'Day', podany jako drugi parametr funkcji TO_CHAR(). Nakazuje on
funkcji TO_CHAR() konwersj daty przechowywanej w polu log_time na posta dnia tygodnia.
Nastpnie stosowany jest operator NOT IN, ktry powoduje wykluczenie soboty (Saturday)
i niedzieli (Sunday) z listy dozwolonych dni.
Naley pamita, e baza danych Oracle rozrnia wielko liter podczas dopasowania. Dlatego te jeli podano 'Day' jako drugi parametr funkcji TO_CHAR(), dni tygodnia na licie znajdujcej si po prawej stronie operatora NOT IN naley poda jako: 'Saturday', 'Sunday'. Miayby one
posta 'SATURDAY', 'SUNDAY', gdyby drugi parametr funkcji TO_CHAR() zosta podany jako 'DAY'.
Powysze polecenia powoduj przeprowadzenie wszystkich wymaganych modyfikacji struktury bazy danych. Po ich wykonaniu mona wic przej do przykadu, ktrego zadaniem jest zilustrowanie sposobw tworzenia transakcji poprzez wykonanie polecenia DML w trybie OCI_DEFAULT,
a nastpnie wyranego zakoczenia tej transakcji po wykonaniu kolejnego polecenia, ale
w trybie OCI_COMMIT_ON_SUCCESS.
W rzeczywistoci oczywicie moe zaj potrzeba uycia wicej ni tylko dwch polece
w transakcji. W tym celu mona wykona w trybie OCI_DEFAULT wszystkie polecenia (poza ostatnim), ktre maj zosta zgrupowane w pojedynczej transakcji, a nastpnie wykona ostatnie
polecenie w trybie OCI_COMMIT_ON_SUCCESS transakcja bdzie zakoczona.
Graficzne przedstawienie caego procesu pokazano na rysunku 4.3.
Przedstawiony poniej skrypt prezentuje, w jaki sposb architektura pokazana na rysunku 4.3
moe by zaimplementowana w PHP. Warto zauway, e w przeciwiestwie do funkcji login(),
omwionej w podrozdziale Przykad uycia podprogramu skadowanego, ktry znajduje si
w rozdziale 3., przedstawiona poniej funkcja login() zatrzymuje wykonywanie i zwraca

115

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

Rysunek 4.3. Graficzne przedstawienie procesu wykonywania omwionego powyej bloku kodu

warto false, kiedy wstawienie rekordu do tabeli logons zakoczy si niepowodzeniem. Ma


to sens, poniewa obecnie nowy rekord jest wstawiany do tabeli logons nie tylko w celu zapisania
informacji o logowaniu, ale take sprawdzenia, czy wstawiane dane stosuj si do zasad biznesowych. Wymienione zasady oznaczaj, e do tabeli logons nie moe by wstawiony aden rekord
zawierajcy w kolumnie log_time dat, dla ktrej dniem tygodnia jest sobota bd niedziela.
<?php
// Plik: userLoginTrans.php.
function login($usr, $pswd) {
if(!$rsConnection = oci_connect('usr', 'usr', '//localhost/orcl')) {
$err = oci_error();
trigger_error('Nie mona nawiza poczenia z baz danych: '
. $err['message'], E_USER_ERROR);
};
$query = "SELECT full_name, num_logons FROM accounts
WHERE usr_id = :userid AND pswd = :passwd";
$stmt = oci_parse($rsConnection,$query);
oci_bind_by_name($stmt, ':userid', $usr);
oci_bind_by_name($stmt, ':passwd', $pswd);
if (!oci_execute($stmt)) {
$err = oci_error($stmt);
trigger_error('Wykonanie zapytania zakoczyo si niepowodzeniem: '
. $err['message'], E_USER_ERROR);
}
if (!$arr = oci_fetch_array($stmt, OCI_ASSOC)) {
print "Podano nieprawidow nazw uytkownika lub haso.";
return false;

116

Rozdzia 4. Transakcje

?>

}
$num_logons=$arr['NUM_LOGONS']+1;
oci_free_statement($stmt);
$query = "UPDATE accounts SET num_logons = num_logons + 1";
$stmt = oci_parse($rsConnection,$query);
if (!oci_execute($stmt, OCI_DEFAULT)) {
$err = oci_error($stmt);
trigger_error('Operacja uaktualnienia zakoczya si niepowodzeniem: '
. $err['message'], E_USER_WARNING);
return false;
}
oci_free_statement($stmt);
$query = "INSERT INTO logons VALUES (:userid, SYSDATE)";
$stmt = oci_parse($rsConnection,$query);
oci_bind_by_name($stmt, ':userid', $usr);
if (!oci_execute($stmt, OCI_COMMIT_ON_SUCCESS)) {
$err = oci_error($stmt);
trigger_error('Operacja wstawienia zakoczya si niepowodzeniem: '
. $err['message'], E_USER_WARNING);
if ($err['code']=='02290'){
print "Nie mona nawiza poczenia w sobot lub niedziel.";
}
return false;
}
print "Witaj ".$arr['FULL_NAME']."<br/>";
print "Odwiedzie nas ju ".$num_logons." raz(y)";
session_start();
$_SESSION['user']=$usr;
return true;

Jak ju wczeniej wspomniano, kolumna num_logons w tabeli accounts przechowuje liczb


zakoczonych powodzeniem operacji logowania kadego uytkownika. W skrypcie zdefiniowano polecenie UPDATE, zwikszajce warto pola num_logons w rekordzie reprezentujcym
uytkownika, ktrego dane uwierzytelniajce zostay uyte podczas procesu uwierzytelniania.
Poprzez wykonanie tego polecenia w trybie OCI_DEFAULT nastpuje utworzenie nowej transakcji. Ma to sens, poniewa wwczas istnieje moliwo wycofania zmian wprowadzonych przez
operacj UPDATE, jeli kolejna operacja wstawiania danych do tabeli logons zakoczy si niepowodzeniem.
Jeeli wykonanie operacji UPDATE zakoczy si niepowodzeniem, nastpi opuszczenie funkcji
login() i zwrcenie wartoci false wywoujcemu j skryptowi. W ten sposb skrypt otrzymuje informacje, e uwierzytelnienie nie powiodo si.
Nastpnie w omawianym przykadzie zdefiniowane jest polecenie INSERT, ktre jest wykonywane
po zakoczonym powodzeniem uwierzytelnieniu uytkownika. Wykonanie go powoduje zwikszenie licznika informujcego o przeprowadzonej liczbie prawidowych operacji logowania.

117

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

Wykonanie polecenia INSERT w trybie OCI_COMMIT_ON_SUCCESS w omawianym skrypcie gwarantuje, e transakcja zostanie zatwierdzona w przypadku powodzenia operacji, a w przeciwnym razie wycofana. Oznacza to, e zmiany wprowadzone zarwno przez polecenie INSERT,
jak i UPDATE albo stan si trwae, albo bd wycofane.
Jak Czytelnik zapewne pamita, wartoci zwrotn funkcji oci_error() jest tablica asocjacyjna dwch elementw. Pierwszy z nich code zawiera kod bdu Oracle, a drugi, message
komunikat bdu opisujcy ten bd. W omawianym przykadzie nastpuje sprawdzenie,
czy kod bdu Oracle jest rwny 02290. Jeeli tak, oznacza to wystpienie bdu zwizanego
ze zamaniem naoonego ograniczenia. Poniewa w tabeli logons zdefiniowano tylko jedno
ograniczenie (uniemoliwiajce wstawiania nowych rekordw do tabeli logons w soboty i niedziele), mona poinformowa uytkownika o braku moliwoci uzyskania poczenia w sobot
bd niedziel.
Jeeli w omawianym skrypcie wykonanie polecenia INSERT zakoczy si niepowodzeniem,
nastpi zakoczenie dziaania funkcji login() wraz z wartoci zwrotn false. Wskazuje to
wywoujcemu j skryptowi, e uwierzytelnienie nie powiodo si. W przypadku uwierzytelnienia
zakoczonego powodzeniem mona podj odpowiednie dziaania, na przykad wywietli
komunikat powitania i utworzy now sesj.
Aby teraz zobaczy w dziaaniu nowo utworzon funkcj login(), mona wykorzysta poniszy prosty skrypt:
<?php
// Plik: testLoginTrans.php.
require_once "userLoginTrans.php";
if (login('bob','pswd')) {
if (isset($_SESSION['user'])) {
print '<p>'.'Twoja nazwa konta: '.$_SESSION['user'].'</p>';
} else {
print '<p>'.'Zmienna sesji przedstawiajca nazw konta
nie zostaa ustawiona.'.'</p>';
}
}else {
print '<p>'.'Uwierzytelnienie zakoczyo si niepowodzeniem'.'</p>';
}
?>

Jeeli przedstawiony powyej skrypt testLoginTrans.php zostanie uruchomiony w sobot lub


niedziel, spowoduje wywietlenie nastpujcego komunikatu:
Nie mona nawiza poczenia w sobot lub niedziel.
Uwierzytelnienie zakoczyo si niepowodzeniem.

Jednak uruchomienie skryptu w dniu roboczym spowoduje wygenerowanie nastpujcych


danych wyjciowych:

118

Rozdzia 4. Transakcje

Witaj Bob Robinson


Odwiedzie nas ju 1 raz(y)
Twoja nazwa konta: bob

Kade kolejne uruchomienie skryptu testLoginTrans.php w dniu roboczym spowoduje zwikszenie licznika odwiedzin strony przez uytkownika Bob Robinson. Jednak wykonanie tego
skryptu w sobot lub niedziel nie powoduje zwikszenia wartoci licznika. Powyszy test
udowadnia, e wszystko dziaa zgodnie z zaoeniami.

Przenoszenie kodu transakcyjnego do bazy danych


Teraz, gdy Czytelnik dysponuje ju dziaajcym rozwizaniem transakcyjnym zaimplementowanym przede wszystkim w PHP, warto zastanowi si, w jaki sposb mona zmniejszy ilo
kodu PHP poprzez przeniesienie czci logiki biznesowej aplikacji do bazy danych.

Uywanie wyzwalaczy
Prac mona rozpocz od zdefiniowania wyzwalacza BEFORE INSERT, obejmujcego tabel
logons, ktry bdzie automatycznie uaktualnia tabel accounts poprzez zwikszanie wartoci
pola num_logons w odpowiednim rekordzie. W ten sposb zostanie wyeliminowana potrzeba
wykonywania tej operacji UPDATE z poziomu kodu PHP.
Przedstawione poniej polecenie SQL powoduje utworzenie wyzwalacza. Naley je wykona
z poziomu narzdzia SQL*Plus po nawizaniu poczenia z baz danych jako usr/usr:
CREATE OR REPLACE TRIGGER logons_insert
BEFORE INSERT
ON logons
FOR EACH ROW
BEGIN
UPDATE accounts
SET num_logons = num_logons + 1
WHERE usr_id = :new.usr_id;
END;
/

Po utworzeniu przedstawionego powyej wyzwalacza logons_insert naley z kodu funkcji


login(), ktra znajduje si w skrypcie userLoginTrans.php, usun poniszy fragment:
$query = "UPDATE accounts SET num_logons = num_logons + 1";
$stmt = oci_parse($rsConnection,$query);
if (!oci_execute($stmt, OCI_DEFAULT)) {
$err = oci_error($stmt);
trigger_error('Operacja uaktualnienia zakoczya si niepowodzeniem: '
. $err['message'], E_USER_WARNING);

119

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

return false;
}
oci_free_statement($stmt);

Warto zwrci uwag, e powysza modyfikacja funkcji login() nie wymaga zmiany istniejcego kodu, ktry implementuje t funkcj. Dlatego te w celu sprawdzenia uaktualnionej wersji
funkcji login() nadal mona wykorzysta skrypt testLoginTrans.php, przedstawiony w poprzedniej sekcji. Powinien on wygenerowa takie same jak poprzednio dane wyjciowe.

Wycofanie na poziomie polecenia


Przegldajc kod uaktualnionej funkcji login(), Czytelnik moe zauway, e nie powoduje
ona wykonania jakiegokolwiek polecenia w trybie OCI_DEFAULT, a tym samym nie tworzy
transakcji. Zamiast tego polecenie INSERT jest wykonywane w trybie OCI_COMMIT_ON_SUCCESS.
Oznacza to, e kady bd wykryty podczas dziaania polecenia INSERT spowoduje wycofanie
wszystkich zmian wprowadzonych przez polecenie INSERT. Z kolei jeeli wykonanie polecenia
INSERT zakoczy si powodzeniem, zmiany zostan automatycznie zatwierdzone.
Jak dotd wszystko idzie dobrze. Co si jednak zdarzy, jeli polecenie UPDATE, wywoane z poziomu wyzwalacza, zakoczy swoje dziaanie niepowodzeniem? Czy spowoduje to wycofanie
zmian wprowadzonych przez polecenie INSERT? Prostym testem pomagajcym w odpowiedzi na
te pytania jest tymczasowe zmodyfikowanie polecenia UPDATE w wyzwalaczu logons_trigger
w taki sposb, aby dziaanie operacji UPDATE zawsze koczyo si niepowodzeniem. Nastpnie
naley uruchomi skrypt testLoginTrans.php, ktry omwiono w podrozdziale Nadzorowanie
transakcji z poziomu PHP, i zobaczy co si zdarzy.
W celu ponownego utworzenia wyzwalacza, aby wykonanie jego polecenia UPDATE zawsze
koczyo si niepowodzeniem, mona uy przedstawionego poniej polecenia SQL:
CREATE OR REPLACE TRIGGER logons_insert
BEFORE INSERT
ON logons
FOR EACH ROW
BEGIN
UPDATE accounts
SET num_logons = num_logons + 'str'
WHERE usr_id = :new.usr_id;
END;
/

Trzeba koniecznie zwrci uwag na fakt, e chocia wykonanie polecenia UPDATE w wyzwalaczu zawsze bdzie koczyo si niepowodzeniem, sam wyzwalacz zostanie poprawnie skompilowany.
Teraz, po uruchomieniu skryptu testLoginTrans.php, powinny zosta wywietlone nastpujce
dane wyjciowe:
Uwierzytelnienie zakoczyo si niepowodzeniem

120

Rozdzia 4. Transakcje

Jak mona si przekona, proces uwierzytelniania zakoczy si niepowodzeniem. Aby upewni si, e wykonanie polecenia INSERT w tabeli logons rwnie bdzie miao taki wynik, mona
oblicza liczb rekordw tabeli przed i po wykonaniu skryptu testLoginTrans.php. Taki efekt
da si osign za pomoc poniszego polecenia SQL, ktre wydano z poziomu narzdzia
SQL*Plus po nawizaniu poczenia z baz danych jako usr/usr:
SELECT count(*) FROM logons;

Czytelnik powinien przekona si, e po wykonaniu skryptu testLoginTrans.php liczba rekordw


tabeli logons pozostanie taka sama. Stanowi to dowd, e niepowodzenie uaktualnienia tabeli
logons za pomoc wyzwalacza logons_insert BEFORE INSERT, obejmujcego tabel accounts, powoduje take wycofanie zmian wprowadzonych przez polecenie INSERT.
Oglnie rzecz biorc, jeeli w trakcie wykonywania wyzwalacza nastpi bd, wycofane zostan wszystkie operacje, ktre spowodoway uruchomienie go. Wynika to z dziaania tak zwanego wycofywana na
poziomie rekordu czyli kady bd powstay podczas wykonywania polecenia spowoduje wycofanie
wszystkich zmian wprowadzonych przez to polecenie.

Jednak powysze stwierdzenie nie zawsze jest prawdziwe. Na przykad wyzwalacz logons_insert
moe zosta zaimplementowany w taki sposb, e efekty dziaania polecenia INSERT nie zostan wycofane, kiedy wykonanie polecenia UPDATE z tego wyzwalacza zakoczy si niepowodzeniem. Warto przeanalizowa przedstawion poniej wersj wyzwalacza logons_insert:
CREATE OR REPLACE TRIGGER logons_insert
BEFORE INSERT
ON logons
FOR EACH ROW
BEGIN
UPDATE accounts
SET num_logons = num_logons + 'str'
WHERE usr_id = :new.usr_id;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
/

Teraz, po uruchomieniu skryptu testLoginTrans.php powinny zosta wywietlone dane wyjciowe o podobnej postaci:
Witaj Bob Robinson
Odwiedzie nas ju 3 raz(y)
Twoja nazwa konta: bob

Nastpnie jeeli skrypt zostanie uruchomiony ponownie, wywietlana liczba operacji logowania pozostanie taka sama. Jednak po sprawdzeniu liczby rekordw tabeli logons, jak przedstawiono we wczeniejszej czci podrozdziau, bdzie mona dostrzec, e kolejne wykonanie
skryptu testLoginTrans.php spowodowao zwikszenie wartoci tej liczby.

121

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

Wskazuje to, e chocia wykonanie polecenia UPDATE z wyzwalacza zakoczyo si niepowodzeniem, wykonanie polecenia INSERT zakoczyo si powodzeniem. Wynika to z faktu, e
omwiony powyej wyzwalacz logons_insert powoduje ciche zignorowanie jakiegokolwiek bdu
zgaszanego podczas jego wykonywania. W sekcji WHEN OTHERS ktra jest jedyn procedur
obsugi wyjtkw w czci wyzwalacza odpowiedzialnej za obsug wyjtkw ustalono
warto NULL.
W wikszoci przypadkw zastosowanie powyej techniki nie jest zalecane, poniewa powoduje zmian
oczekiwanego sposobu zachowania bazy danych. Rozsdne zaoenie jest takie, e jeli podczas wykonywania jakiegokolwiek polecenia SQL wystpi bd, modyfikacje wprowadzone przez to polecenie s
automatycznie wycofywane.

Dlatego te zamiast ustawia warto NULL w procedurze obsugi wyjtkw, naley utworzy
kod, ktry bdzie podejmowa odpowiednie dziaania w odpowiedzi na wystpienie bdu.
Na przykad mona wykorzysta procedur RAISE_APPLICATION_ERROR w celu wygenerowania
zdefiniowanego przez uytkownika bdu ORA. Znajdujcy si poniej fragment kodu pokazuje, w jaki sposb wyzwalacz logons_insert mgby zosta zmodyfikowany, aby wywoywa
RAISE_APPLICATION_ERROR z poziomu procedury obsugi bdw:
CREATE OR REPLACE TRIGGER logons_insert
BEFORE INSERT
ON logons
FOR EACH ROW
BEGIN
UPDATE accounts
SET num_logons = num_logons + 'str'
WHERE usr_id = :new.usr_id;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20000, 'Uaktualnienie licznika nie powiodo si.');
END;
/

W powyszym wyzwalaczu procedura obsugi wyjtkw wyranie wywouj procedur RAISE_


APPLICATION_ERROR w celu wygenerowania bdu ORA zdefiniowanego przez uytkownika.
Jeeli w pliku konfiguracyjnym php.ini parametr display_errors ma warto On, omwiony w podrozdziale Nadzorowanie transakcji z poziomu PHP skrypt userLoginTrans.php spowoduje wywietlenie
komunikatu bdu wskazanego jako drugi parametr procedury RAISE_APPLICATION_ERROR.

Teraz, po uruchomieniu skryptu testLoginTrans.php, powinien zosta wywietlony nastpujcy komunikat:


Uwierzytelnienie zakoczyo si niepowodzeniem

122

Rozdzia 4. Transakcje

Liczba rekordw w tabeli logons powinna pozosta taka sama, co oznacza, e niepowodzenie
operacji uaktualnienia tabeli accounts przez wyzwalacz powoduje nie tylko wycofanie zmian
wprowadzonych przez polecenie UPDATE, ale rwnie przez polecenie INSERT.
Przed zakoczeniem pracy z tym przykadem naley si upewni o ponownym utworzeniu
wyzwalacza logons_trigger, aby klauzula SET w jego poleceniu UPDATE przedstawiaa si nastpujco:
SET num_logons = num_logons + 1

Rozwaania dotyczce izolacji transakcji


Kiedy transakcja modyfikuje rekord tabeli bazy danych, Oracle nakada na niego blokad
utrzymywan a do chwili zatwierdzenia bd wycofania tej transakcji. Celem takiego zachowania jest niedopuszczenie do sytuacji, w ktrej dwie wspbiene transakcje bd modyfikoway ten sam rekord.
Bardzo wane jest, aby w tym miejscu wspomnie, e rekordy z naoonymi blokadami nadal
mog by odczytywane zarwno przez transakcje uaktualniajce rekordy, jak i inne transakcje. Rnica midzy dwiema wymienionymi transakcjami polega na tym, e transakcja nakadajca blokad moe zauway zmiany natychmiast po wykonaniu polecenia modyfikujcego
te rekordy. Natomiast inna transakcja nie moe zobaczy tych zmian a do chwili zatwierdzenia zmian przez transakcj, ktra naoya blokad.
Podczas gdy zastosowany w bazie danych Oracle mechanizm nakadania blokad zosta szczegowo omwiony w dokumentacji Oracle (w rozdziale Data Concurrency and Consistency
w podrczniku uytkownika Oracle Database Concepts), w podrozdziale przedstawiono oglny opis dziaania izolacji transakcji w aplikacjach PHP/Oracle.

Ktr funkcj rozszerzenia OCI8 suc do nawizywania


poczenia naley wybra?
Jak Czytelnik pamita z podrozdziau Funkcje OCI8, ktre su do nawizywania poczenia
z Oracle znajdujcego si w rozdziale 2., rozszerzenie PHP OCI8 oferuje trzy rne funkcje suce do nawizywania poczenia z baz danych Oracle. S to oci_connect(), oci_new_connect()
oraz oci_pconnect(). Jedyn rnic midzy tymi funkcjami jest rodzaj nawizywanego poczenia z baz danych.
Zarwno funkcja oci_connect(), jak i oci_pconnect() uywaj bufora poczenia bazy danych,
tym samym eliminujc koszt nawizania poczenia w trakcie kadego dania. Rnica midzy
dwiema wymienionymi funkcjami polega na tym, e poczenie nawizane przez oci_connect()

123

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

zostaje zwolnione po zakoczeniu wykonywania skryptu, podczas gdy poczenia nawizane


przez funkcj oci_pconnect() s trwae midzy wykonywaniem kolejnych skryptw.
W przeciwiestwie do oci_connect() i oci_pconnect() funkcja oci_new_connect() nie uywa
bufora pocze i zawsze powoduje nawizanie nowego poczenia. Trzeba j stosowa, gdy
zachodzi potrzeba utworzenia w skrypcie dwch lub wikszej liczby wspbienych transakcji. Przedstawiony poniej przykad prezentuje uycie funkcji oci_new_connect() w dziaaniu.
W poniszym skrypcie warto zwrci uwag na wykorzystanie funkcji oci_new_connect() w celu
utworzenia wspbienej transakcji. Chocia do utworzenia pierwszej transakcji w skrypcie
uyto funkcji oci_connect(), w celu nawizania nowego poczenia zastosowano funkcj oci_
new_connect().
<?php
// Plik: newConns.php.
function select_emp_job ($conn, $jobno) {
$query = "SELECT employee_id, first_name, last_name, salary
FROM employees WHERE job_id =:jobid";
$stmt = oci_parse($conn,$query);
oci_bind_by_name($stmt, ':jobid', $jobno);
if (!oci_execute($stmt, OCI_DEFAULT)) {
$err = oci_error($stmt);
trigger_error('Wykonanie zapytania zakoczyo si niepowodzeniem: '
. $err['message'], E_USER_ERROR);
};
print '<table border="1">';
while ($emp = oci_fetch_array($stmt, OCI_ASSOC)) {
print '<tr>';
print '<td>'.$emp['EMPLOYEE_ID'].'</td>';
print '<td>'.$emp['FIRST_NAME'].'&nbsp;'.$emp['LAST_NAME']. '</td>';
print '<td>'.$emp['SALARY'].'</td>';
print '</tr>';
}
print '</table>';
}
if(!$conn1 = oci_connect('hr', 'hr', '//localhost/orcl')) {
$err = oci_error();
trigger_error('Nie mona nawiza poczenia z baz danych: '
. $err['message'], E_USER_ERROR);
};
if(!$conn2 = oci_new_connect('hr', 'hr', '//localhost/orcl')) {
$err = oci_error();
trigger_error('Nie mona nawiza poczenia z baz danych: '
. $err['message'], E_USER_ERROR);
};
$jobno = 'AD_VP';
$query = "UPDATE employees SET salary = 18000 WHERE job_id=:jobid";
$stmt = oci_parse($conn1,$query);
oci_bind_by_name($stmt, ':jobid', $jobno);

124

Rozdzia 4. Transakcje

if (!oci_execute($stmt, OCI_DEFAULT)) {
$err = oci_error($stmt);
trigger_error('Wykonanie zapytania zakoczyo si niepowodzeniem: '
. $err['message'], E_USER_ERROR);
};
print "<h2>Testowanie izolacji transakcji!</h2>";
print "<h4>Transakcja A w ramach poczenia conn1:</h4>";
print "<p>(wyniki po uaktualnieniu oraz przed zatwierdzeniem transakcji
w ramach poczenia conn1)</p>";
select_emp_job($conn1, $jobno);
print "<h4>Transakcja B w ramach poczenia conn2:</h4>";
print "<p>(wyniki po uaktualnieniu oraz przed zatwierdzeniem transakcji
w ramach poczenia conn1)</p>";
select_emp_job($conn2, $jobno);
if (!oci_commit($conn1)) {
$err = oci_error($conn1);
trigger_error('Zatwierdzenie transakcji zakoczyo si niepowodzeniem: '
.$err['message'], E_USER_ERROR);
}
print "<h4>Transakcja B w ramach poczenia conn2:</h4>";
print "<p>( wyniki po uaktualnieniu oraz po zatwierdzeniu transakcji
w ramach poczenia conn1)</p>";
select_emp_job($conn2, $jobno);
$query = "UPDATE employees SET salary = 17000 WHERE job_id=:jobid";
$stmt = oci_parse($conn1,$query);
oci_bind_by_name($stmt, ':jobid', $jobno);
if (!oci_execute($stmt)) {
$err = oci_error($stmt);
trigger_error('Wykonanie zapytania zakoczyo si niepowodzeniem: '
. $err['message'], E_USER_ERROR);
};
?>

Na rysunku 4.4 pokazano dane wyjciowe powyszego skryptu. Jak mona zobaczy, zmiany
wprowadzone przez operacj UPDATE przeprowadzon w transakcji dziaajcej w ramach poczenia conn1 z baz danych s widoczne wewntrz tej transakcji natychmiast po wykonaniu
polecenia UPDATE. Nie s natomiast widoczne dla wspbienej transakcji dziaajcej w ramach
poczenia conn2 a do chwili zatwierdzenia pierwszej transakcji.
Powracajc do kodu rdowego omawianego skryptu newConns.php: warto zwrci uwag,
e wszystkie polecenia SQL uyte w skrypcie zostay wykonane w trybie OCI_DEFAULT. Gwarantuje on natychmiastowe zatwierdzenie transakcji.
Naley rwnie zwrci uwag, e pierwsze poczenie w skrypcie zostao nawizane za pomoc funkcji oci_connect(). Poniewa jest to pierwsze poczenie, bufor pocze przypisany
temu skryptowi jest pusty, wic funkcja oci_connect() nawie nowe poczenie z baz danych.

125

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

Rysunek 4.4. Testowanie izolacji transakcji


Transakcje wspbiene trzeba tworzy z uyciem transakcyjnie izolowanych pocze. Podczas gdy
pierwsze poczenie w skrypcie moe by utworzone za pomoc funkcji oci_connect(), w celu utworzenia
kolejnych, transakcyjnie izolowanych pocze w skrypcie trzeba wykorzysta funkcj oci_new_connect().

Nastpnie w celu utworzenia nowego, transakcyjnie izolowanego poczenia w skrypcie nastpuje wywoanie funkcji oci_new_connect().
Poprzez wykonanie polecenia UPDATE w trybie OCI_DEFAULT w ramach poczenia conn1 nastpuje utworzenie transakcji w tym poczeniu.
Po wykonaniu polecenia UPDATE efekty tej operacji bd widoczne dla innych operacji przeprowadzanych wewntrz tej samej transakcji. Aby to udowodni, w skrypcie wywietlane s
rekordy zmodyfikowane przez polecenie UPDATE wewntrz tej samej transakcji przed jej zatwierdzeniem. Jak wida na rysunku 4.4, polecenie SELECT zwraca nowe wartoci uaktualnionych rekordw.
126

Rozdzia 4. Transakcje

Jednak podczas przeprowadzania operacji SELECT we wspbienej transakcji nadal bd widoczne pocztkowe wartoci uaktualnionych rekordw. Wynika to z faktu, e wspbiene transakcje s izolowane od zmian wprowadzonych przez niezatwierdzone transakcje. Gdy transakcja zostanie zatwierdzona, wszystkie wprowadzone przez ni zmiany stan si widoczne dla
innych transakcji.
Wreszcie, za pomoc funkcji UPDATE nastpuje przywrcenie wartoci pocztkowych uaktualnionym rekordom.

Kwestie zwizane z wspbienym uaktualnianiem


Podczas projektowania aplikacji, ktra bdzie modyfikowaa dane bazy danych w rodowisku
wielodostpnym, programista bdzie musia zmierzy si z dwoma wyzwaniami:
Q Zapewnienie poprawnoci i spjnoci danych.
Q Zagwarantowanie, e wydajno nie ucierpi z powodu nakadania blokad.

Chocia Oracle dostarcza zestaw funkcji, ktre mog pomc osign wymienione powyej
cele, prawidowe wykorzystanie ich jest ju zadaniem programisty. Przedstawione poniej
podrozdziay koncentruj si na pewnych kwestiach zwizanych z wspbienym uaktualnianiem danych, ktre mog pojawi si w rodowisku wielodostpnym podczas nieprawidowego uywania transakcji.

Kwestie zwizane z nakadaniem blokad


Jak ju wczeniej wspomniano, Oracle nakada blokad na uaktualniany rekord, aby inne
transakcje nie miay moliwoci jego modyfikacji a do zakoczenia uaktualniajcej go transakcji. Podczas gdy celem takiego zachowania jest zagwarantowanie poprawnoci danych uywanych w rodowisku wielodostpnym, w kiepsko zaprojektowanej aplikacji moe ono spowodowa powstanie znaczcego obcienia.
Warto przyjrze si prostemu skryptowi pokazujcemu, jak kiepsko zaprojektowany skrypt,
ktry wykonuje dugotrwajce operacje, moe spowodowa problemy zwizane z nakadaniem
blokad, jeli zostanie uyty w rodowisku wielodostpnym. Przedstawiony poniej skrypt
updateSleep.php wykonuje nastpujce kroki:
Q Tworzy transakcj.
Q Uaktualnia niektre rekordy w tabeli employees.
Q Wstrzymuje na 20 sekund wykonywanie skryptu.
Q Wycofuje transakcj.

Wstrzymanie wykonywania poniszego skryptu za pomoc funkcji sleep() pozwala na symulacj przeprowadzania operacji wymagajcej ogromnej iloci oblicze.

127

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

<?php
// Plik: updateSleep.php.
if(!$dbConn = oci_connect('hr', 'hr', '//localhost/orcl')) {
$err = oci_error();
trigger_error('Nie mona nawiza poczenia z baz danych: '
. $err['message'], E_USER_ERROR);
};
$jobno = 'AD_VP';
$query = "
UPDATE employees
SET salary = salary*1.1
WHERE job_id=:jobid";
$stmt = oci_parse($dbConn,$query);
oci_bind_by_name($stmt, ':jobid', $jobno);
if (!oci_execute($stmt, OCI_DEFAULT)) {
$err = oci_error($stmt);
trigger_error('Wykonanie zapytania zakoczyo si niepowodzeniem: '
. $err['message'], E_USER_ERROR);
};
$updrows = oci_num_rows($stmt);
print 'Uaktualniono '.$updrows. ' rekord(w)'.'<br/>';
sleep(20);
oci_rollback($dbConn);
print 'Transakcja zostaa wycofana.';
?>

W powyszym skrypcie polecenie UPDATE jest wykonywane w trybie OCI_DEFAULT, nakazujc


bazie danych Oracle utworzenie transakcji.
Nastpnie wywoanie funkcji sleep() powoduje wstrzymanie wykonywania skryptu na dwadziecia sekund, symulujc tym samym przeprowadzanie operacji wymagajcej ogromnej iloci oblicze.
Wreszcie, za pomoc funkcji oci_rollback() nastpuje wycofanie transakcji. W rzeczywistoci ten krok jest opcjonalny, poniewa transakcja zostaje wycofana automatycznie, gdy skrypt
koczy dziaanie.
Teraz uruchomiony skrypt updateSleep.php, ktry omwiono wczeniej, uaktualni wszystkie
rekordy Administration Vice President w tabeli employees, zablokuje je na dwadziecia sekund, a nastpnie wycofa transakcj.
Jeeli w trakcie wymienionych dwudziestu sekund wystpi prba uaktualnienia tych samych
rekordw, ale z poziomu innego skryptu, na przykad za pomoc narzdzia SQL*Plus, bd
one zablokowane, a skrypt updateSleep.php zwolni blokad naoon na wymienione rekordy.
Mora z powyszego skryptu jest taki, e jeli skrypt ma przeprowadzi dugotrwajc operacj w bardzo obcionym rodowisku wielodostpnym, zawsze dobrym pomysem bdzie zamknicie wszystkich aktywnych transakcji wewntrz skryptu przed rozpoczciem przetwarzania tej operacji.

128

Rozdzia 4. Transakcje

Utracone uaktualnienia
Omwiony powyej przykad pokaza, jak kiepsko zaprojektowana aplikacja transakcyjna moe na dugo zablokowa zasoby bazy danych, co uniemoliwi wspbienym transakcjom uzyskanie dostpu do tych zasobw w rozsdnym czasie. Jednak warto zwrci uwag, e zastosowanie podejcia bez blokad podczas modyfikowania danych bazy danych w rodowisku
wielodostpnym moe spowodowa inny problem utracone uaktualnienia. Aby zrozumie,
na czym polega problem utraconych uaktualnie, naley przeanalizowa kroki, ktre interaktywna aplikacja zwykle przeprowadza podczas modyfikacji informacji przechowywanych
w bazie danych:
Q Wybr danych z bazy danych.
Q Wywietlenie danych uytkownikowi.
Q Oczekiwanie na dziaanie uytkownika.
Q Uaktualnienie danych w bazie danych.

Powinno by cakiem oczywiste, e kiedy w powyszym przykadzie aplikacja czeka na dziaanie uytkownika, inny uytkownik moe spowodowa zmian danych. Dlatego te jeeli
pierwszy uytkownik bdzie kontynuowa proces uaktualniania danych, zmiany wprowadzone
przez drugiego uytkownika zostan utracone.
Problem mona lepiej zrozumie na podstawie przykadu. Warto wic spojrze na skrypt
updateQuickForm.php, ktry implementuje powysze kroki za pomoc pakietu PEAR o nazwie
HTML_QuickForm. Po uruchomieniu skryptu wykona ona nastpujce kroki:
Q Uaktualni dwa rekordy w tabeli employees.
Q Wygeneruje formularz proszcy uytkownika o zatwierdzenie bd wycofanie zmian.
Q Zakoczy dziaanie, wycofujc wprowadzone zmiany.

Za pomoc formularza wygenerowanego przez skrypt uytkownik moe albo zatwierdzi, albo
wycofa zmiany, a nastpnie musi klikn przycisk Wylij. Gdy to zrobi, skrypt zostanie wywoany ponownie, tym razem wykonujc ponisze kroki:
Q Uaktualnienie tych samych rekordw w tabeli employees.
Q Zatwierdzenie lub wycofanie zmian w zalenoci od decyzji uytkownika.
Q Zakoczenie dziaania skryptu.

Dane wyjciowe wygenerowane przez skrypt zostay pokazane na rysunku 4.5.


Jednak przed uruchomieniem skryptu updateQuickForm.php naley si upewni o zainstalowaniu pakietu PEAR::HTML_QuickForm. Poniewa pakiet HTML_QuickForm jest uzaleniony od
innego pakietu o nazwie HTML_Common, w pierwszej kolejnoci naley zainstalowa drugi z wymienionych. Zakadajc, e w systemie znajduje si zainstalowany i skonfigurowany PEAR Installer,
w celu pobrania i instalacji pakietu HTML_Common mona wyda ponisze polecenie:
$ pear install HTML_Common

129

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

Rysunek 4.5. Dane wyjciowe skryptu updateQuickForm.php wywietlone w przegldarce internetowej

Po instalacji pakietu HTML_Common mona przystpi do pobrania i instalacji pakietu HTML_Quick


Form. Naley wyda polecenie:
$ pear install HTML_QuickForm

Po przeprowadzeniu powyszych krokw mona uruchomi skrypt updateQuickForm.php, ktrego kod rdowy przedstawiono poniej:
<?php
// Plik: updateQuickForm.php.
require_once 'HTML/QuickForm.php';
if(!$dbConn = oci_connect('hr', 'hr', '//localhost/orcl')) {
$err = oci_error();
trigger_error('Nie mona nawiza poczenia z baz danych: '
. $err['message'], E_USER_ERROR);
};
$jobno = 'AD_VP';
$query = "
UPDATE employees
SET salary = salary*1.1
WHERE job_id=:jobid";
$stmt = oci_parse($dbConn,$query);
oci_bind_by_name($stmt, ':jobid', $jobno);
if (!oci_execute($stmt, OCI_DEFAULT)) {
$err = oci_error($stmt);
trigger_error('Wykonanie zapytania zakoczyo si niepowodzeniem: '
.$err['message'], E_USER_ERROR);
};
print '<h2>Potwierdzenie uaktualnienia!</h2>';
$updrows = oci_num_rows($stmt);

130

Rozdzia 4. Transakcje

$frm=new HTML_QuickForm('frm1', 'POST');


$frm->addElement('header','msg1','Uaktualniono '.$updrows. '
rekord(w). Czy chcesz zatwierdzi zmiany?');
$grp[] =& HTML_QuickForm::createElement('radio', null, null,'zatwierd', 'C');
$grp[] =& HTML_QuickForm::createElement('radio', null, null,'wycofaj', 'R');
$frm->addGroup($grp, 'trans');
$frm->setDefaults(array('trans' => 'C'));
$frm->addElement('submit','submit','Wylij');
if(isset($_POST['submit'])) {
if ($_POST['trans']=='C'){
oci_commit($dbConn);
print 'Transakcja zostaa zatwierdzona.';
} elseif ($_POST['trans']=='R'){
oci_rollback($dbConn);
print 'Transakcja zostaa wycofana.';
} else {
$frm->display();
}
} else {
$frm->display();
}
?>

Przygldajc si formularzowi pokazanemu na rysunku 4.5, Czytelnik moe pomyle, e po


uaktualnieniu dwch rekordw tabeli employees skrypt czeka na dziaanie uytkownika, pozostawiajc aktywn transakcj. W rzeczywistoci dziaa on zupenie inaczej.
Skrypt podczas pierwszego uruchamiania faktycznie powoduje uaktualnienie tabeli employees, ale
nastpnie wycofuje transakcj. W ten sposb moliwe jest zliczenie liczby rekordw modyfikowanych przez polecenie UPDATE i podanie tej informacji uytkownikowi. Gdy ten wybierze
opcj zatwierd albo wycofaj transakcji i kliknie przycisk Wylij, skrypt ponownie wykona t
sam operacj UPDATE. Tym razem w zalenoci od opcji wybranej przez uytkownika zmiany
wprowadzone przez polecenie UPDATE bd zatwierdzone lub wycofane.
Zalet stosowania powyszej techniki jest to, e przetwarzane rekordy nie zostaj zablokowane w czasie potrzebnym na podjcie decyzji, ktry przycisk klikn: zatwierd lub wycofaj.
Dziki temu w tym samym czasie inne transakcje mog przeprowadza operacje na tych rekordach. Jednak powoduje to powstanie kolejnego problemu utraconych uaktualnie, jak
to zostao omwione we wczeniejszej czci podrozdziau.
Aby unikn problemu utraconych uaktualnie, mona zastosowa strategi blokowania optymistycznego, dziki czemu wartoci uaktualnianych pl nie zostan zmienione, kiedy uytkownik rozpocznie z nimi prac.

131

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

Transakcje autonomiczne
Kontynuujc poprzedni przykad: moe wystpi potrzeba rejestrowania prb uaktualnienia
rekordw w tabeli employees. Aby umoliwi takie zadanie, trzeba utworzy tabel przechowujc
sprawdzane rekordy, jak rwnie wyzwalacz BEFORE UPDATE, ktry obejmuje tabel employees.
Zadaniem wyzwalacza bdzie wstawianie rekordu do nowej tabeli za kadym razem, gdy ktokolwiek sprbuje uaktualni rekord w tabeli employees.
W celu utworzenia wymienionej struktury danych naley wyda nastpujce polecenie SQL:
CONN usr/usr
CREATE TABLE emp_updates(
emp_id NUMBER(6),
job_id VARCHAR2(10),
timedate DATE);
CONN /AS SYSDBA
GRANT INSERT on usr.emp_updates TO hr;
CONN hr/hr
CREATE OR REPLACE TRIGGER emp_updates_trigger
BEFORE UPDATE
ON employees
FOR EACH ROW
BEGIN
INSERT INTO usr.emp_updates VALUES (:new.employee_id, :new.job_id,
SYSDATE);
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001, 'W wyzwalaczu wystpi bd.');
END;
/

Po wykonaniu powyszego polecenia mona uruchomi skrypt updateQuickForm.php, omwiony w poprzednim podrozdziale, i sprawdzi, czy mechanizm kontroli dziaa zgodnie z zaoeniami. W formularzu wygenerowanym przez skrypt naley zaznaczy opcj wycofaj, a nastpnie klikn przycisk Wylij. Teraz przy prbie wywietlenia rekordw tabeli emp_updates
w nastpujcy sposb:
CONN usr/usr;
SELECT * FROM emp_updates;

Czytelnik powinien zobaczy, e tabela emp_updates wci nie zawiera adnych rekordw:
no rows selected

Oznacza to, e po wycofaniu operacji UPDATE nastpio wycofanie rekordu take z tabeli kontrolnej. Takie zachowanie jest oczekiwane, poniewa nie mona wycofa pewnych efektw
transakcji mona albo zatwierdzi wszystkie efekty, albo wszystkie wycofa.

132

Rozdzia 4. Transakcje

Prba zatwierdzenia jedynie polecenia INSERT wykonywanego wewntrz wyzwalacza zakoczy si niepowodzeniem, poniewa w wyzwalaczu niedozwolone jest uycie adnych polece
nadzorujcych transakcj. Dlatego te po prbie utworzenia wyzwalacza emp_updates_trigger
w nastpujcy sposb (trzeba pamita, aby by poczonym jako uytkownik hr wykonujc polecenie CONN hr/hr inaczej tabela employees nie bdzie widoczna i nie uda si utworzy wyzwalacza):
CREATE OR REPLACE TRIGGER emp_updates_trigger
BEFORE UPDATE
ON employees
FOR EACH ROW
BEGIN
INSERT INTO usr.emp_updates VALUES (:new.employee_id,
:new.job_id, SYSDATE);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
/

uruchomienie skryptu updateQuickForm.php spowoduje wywietlenie nastpujcych komunikatw bdw:


Warning: oci_execute()[function.oci-execute]:ORA-04092: cannot
ROLLBACK in a trigger ORA-06512: at "HR.EMP_UPDATES_TRIGGER", line
6 ORA-04092: cannot COMMIT in a trigger ORA-04088: error during
execution of trigger 'HR.EMP_UPDATES_TRIGGER'
Fatal error: Query failed: ORA-04092: cannot ROLLBACK in a trigger
ORA-06512: at "HR.EMP_UPDATES_TRIGGER", line 6 ORA-04092: cannot
COMMIT in a trigger ORA-04088: error during execution of trigger 'HR.
EMP_UPDATES_TRIGGER
Powysze komunikaty bdw zostan wywietlone tylko wtedy, gdy w pliku konfiguracyjnym php.ini
parametr display_errors ma ustawion warto On.

Jednym ze sposobw rozwizania powyszego problemu jest uycie transakcji autonomicznej.


Transakcja autonomiczna jest transakcj wewntrz innej transakcji. Poniewa jest cakowicie niezalena
od wywoujcej j transakcji, pozwala na przeprowadzanie operacji SQL, a nastpnie zatwierdzanie ich
lub wycofywanie bez zatwierdzania lub wycofywania wywoujcej j transakcji.

Zastosowanie transakcji autonomicznej w omawianym przykadzie pozwoli na zatwierdzenie


polecenia INSERT wykonywanego przez wyzwalacz emp_updates_trigger niezalenie od transakcji

133

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa

utworzonej przez skrypt updateQuickForm.php. Dziki temu w tabeli emp_updates zostanie


utworzony rekord, nawet gdy efekty operacji UPDATE wywoanej przez ten wyzwalacz zostan
wycofane.
Przedstawiony poniej fragment kodu pokazuje sposb utworzenia wyzwalacza emp_updates_
trigger, ktry stosuje transakcj autonomiczn.
CREATE OR REPLACE TRIGGER emp_updates_trigger
BEFORE UPDATE
ON employees
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO usr.emp_updates VALUES (:new.employee_id,
:new.job_id, SYSDATE);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
/

Powyszy przykad prezentuje implementacj transakcji autonomicznej w wyzwalaczu bazy


danych. Zastosowanie tutaj transakcji autonomicznej gwarantuje, e rekord kontrolny zostanie utworzony w tabeli emp_updates, niezalenie od tego, czy operacja UPDATE wzgldem tabeli
employees zostanie zatwierdzona, czy wycofana.
Aby sprawdzi nowo utworzony wyzwalacz, naley ponownie uruchomi skrypt updateQuickForm.php i wysa formularz wygenerowany przez skrypt po wybraniu opcji wycofaj. Nastpnie trzeba znw wywietli zawarto tabeli emp_updates (ponownie trzeba pamita o poczeniu na odpowiedniego uytkownika tym razem usr/usr):
SELECT * FROM emp_updates;

Tym razem dane wyjciowe polecenia mog by podobne do przedstawionych poniej:


EMP_ID JOB_ID
TIMEDATE
------- ---------- --------101 AD_VP
29-MAY-06
102 AD_VP
29-MAY-06
101 AD_VP
29-MAY-06
102 AD_VP
29-MAY-06

Warto zwrci uwag, e chocia prba dotyczya uaktualnienia tylko dwch rekordw tabeli
employees, do tabeli kontrolnej emp_updates zostay wstawione cztery rekordy. Trzeba pamita, e w rzeczywistoci skrypt updateQuickForm.php dwukrotnie przeprowadza operacj
UPDATE. Po raz pierwszy w celu obliczenia liczby rekordw przeznaczonych do uaktualnienia.
Natomiast druga operacja faktycznie uaktualnia te rekordy.
134

Rozdzia 4. Transakcje

Podsumowanie
Niektre operacje wykonywane wzgldem bazy danych maj sens jedynie po zgrupowaniu
ich. Klasycznym przykadem jest operacja przelewu rodkw pieninych midzy dwoma
kontami bankowymi. Jedynym sposobem bezpiecznego przeprowadzenia tego rodzaju operacji pozostaje uycie transakcji. Zastosowanie transakcji pozwala na zgrupowanie polece SQL
w logiczne, niewidoczne jednostki pracy, z ktrych kada moe by albo w caoci zatwierdzona, albo w caoci wycofana.
W rozdziale Czytelnik dowiedzia si, kiedy i jak wykorzystywa transakcje w aplikacjach
PHP/Oracle. Analiza rozpocza si od oglnego przedstawienia transakcji Oracle oraz wyjanienia powodw, dla ktrych programista miaby ich uywa w aplikacjach PHP zbudowanych na Oracle. Nastpnie omwiono organizacj aplikacji PHP/Oracle w celu efektywnego
kontrolowania transakcji skoncentrowano si na korzyciach wynikajcych z przeniesienia
logiki biznesowej aplikacji transakcyjnej z PHP do bazy danych. Czytelnik dowiedzia si
rwnie, ktre funkcje rozszerzenia OCI8 suce do nawizywania poczenia naley wybiera
podczas uywania transakcji, a take jak tworzy wspbiene transakcje w ramach tego samego skryptu. Wreszcie zaprezentowano wywoywanie niezalenej transakcji z wewntrz
innej transakcji oraz przedstawiono sytuacje, w ktrych zastosowanie takiego rozwizania
moe by podane.

135

You might also like