Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00513 010259 11030910 na godz. na dobę w sumie
PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa - książka
PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa - książka
Autor: Liczba stron: 392
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-1974-0 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> bazy danych >> oracle - programowanie
Porównaj ceny (książka, ebook, audiobook).

Poznaj niezwykłe możliwości duetu Oracle-PHP i twórz niezawodne aplikacje!

Baza Danych Oracle nie ma sobie równych pod względem wydajności, niezawodności oraz skalowalności. Natomiast skryptowy język PHP dzięki niezwykłej prostocie stosowania stanowi jedno z najpopularniejszych narzędzi budowania aplikacji sieciowych -- nawet dla niezbyt doświadczonych programistów. Budowanie i wdrażanie aplikacji PHP opartych na Oracle pozwala więc na optymalne połączenie potężnych możliwości i solidności z łatwością użycia i krótkim czasem programowania.

Książka 'PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa' zawiera zilustrowany praktycznymi przykładami opis technologii oraz wszystkich narzędzi potrzebnych, aby optymalnie wykorzystać możliwości duetu Oracle-PHP. Dzięki temu podręcznikowi poznasz nowe funkcje PHP i bazy danych Oracle; dowiesz się także, na czym polega programowanie procedur składowanych i obsługa transakcji. Nauczysz się tworzyć niezawodne aplikacje i zapewniać im wyższą wydajność dzięki mechanizmom buforowania, a także używać technologii Ajax z technologiami Oracle Database i funkcjami PHP w celu usprawnienia reakcji aplikacji na działania użytkownika.

Połącz wydajność, skalowalność i niezawodność z łatwością użycia i krótkim czasem programowania!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa Autor: Yuli Vasiliev T³umaczenie: Robert Górczyñski, Artur Przyby³a ISBN: 978-83-246-1974-0 Tytu³ orygina³u: PHP Oracle Web Development: Data processing, Security, Caching, XML, Web Services, and Ajax Format: 170x230, stron: 392 Poznaj niezwyk³e mo¿liwoœci duetu Oracle–PHP i twórz niezawodne aplikacje! • Jak po³¹czyæ PHP i Oracle w celu uzyskania optymalnej wydajnoœci i niezawodnoœci? • Jak wykorzystywaæ funkcje XML w PHP i Oracle? • Jak poprawiæ wydajnoœæ dziêki zastosowaniu buforowania? Baza Danych Oracle nie ma sobie równych pod wzglêdem wydajnoœci, niezawodnoœci oraz skalowalnoœci. Natomiast skryptowy jêzyk PHP dziêki niezwyk³ej prostocie stosowania stanowi jedno z najpopularniejszych narzêdzi budowania aplikacji sieciowych — nawet dla niezbyt doœwiadczonych programistów. Budowanie i wdra¿anie aplikacji PHP opartych na Oracle pozwala wiêc na optymalne po³¹czenie potê¿nych mo¿liwoœci i solidnoœci z ³atwoœci¹ u¿ycia i krótkim czasem programowania. Ksi¹¿ka „PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa” zawiera zilustrowany praktycznymi przyk³adami opis technologii oraz wszystkich narzêdzi potrzebnych, aby optymalnie wykorzystaæ mo¿liwoœci duetu Oracle–PHP. Dziêki temu podrêcznikowi poznasz nowe funkcje PHP i bazy danych Oracle; dowiesz siê tak¿e, na czym polega programowanie procedur sk³adowanych i obs³uga transakcji. Nauczysz siê tworzyæ niezawodne aplikacje i zapewniaæ im wy¿sz¹ wydajnoœæ dziêki mechanizmom buforowania, a tak¿e u¿ywaæ technologii Ajax z technologiami Oracle Database i funkcjami PHP w celu usprawnienia reakcji aplikacji na dzia³ania u¿ytkownika. • Po³¹czenie PHP i Oracle • Przetwarzanie danych • Tworzenie i wywo³ywanie wyzwalaczy • U¿ywanie podprogramów sk³adowanych • Podejœcie zorientowane obiektowo • Obs³uga wyj¹tków • Bezpieczeñstwo • Buforowanie • Aplikacje oparte na XML • Us³ugi sieciowe • Aplikacje oparte na Ajaksie Po³¹cz wydajnoœæ, skalowalnoœæ i niezawodnoœæ z ³atwoœci¹ u¿ycia i krótkim czasem programowania! Spis treści O autorze O recenzencie Wprowadzenie Jakie tematy zostały poruszone w książce? Dla kogo przeznaczona jest ta książka? Konwencje zastosowane w książce Użycie przykładowych kodów Rozdział 1. Rozpoczęcie pracy z PHP i Oracle Dlaczego PHP i Oracle? Prostota i elastyczność Wydajność Niezawodność Co zamiast PHP i Oracle? PHP i MySQL JSF i Oracle Co będzie potrzebne, aby rozpocząć pracę? Wymagane komponenty oprogramowania Rozważania dotyczące produktu Oracle Database Zrozumienie Oracle Database Wybór między wydaniami oprogramowania Oracle Database Pobieranie oprogramowania Oracle Database Rozważania dotyczące PHP Serwer WWW Apache Dlaczego PHP 5? Pobieranie PHP 5 Zmuszenie PHP i Oracle do współpracy Oracle Instant Client Zend Core for Oracle 11 13 15 16 17 17 18 19 20 20 21 21 22 22 23 23 23 25 25 25 26 27 28 28 29 30 30 31 Spis treści Używanie Oracle SQL*Plus Dlaczego warto używać SQL*Plus w programowaniu PHP/Oracle? Nawiązywanie połączenia z bazą danych za pomocą SQL*Plus Wykonywanie skryptów z poziomu SQL*Plus Połączenie wszystkiego razem Utworzenie pierwszej aplikacji PHP/Oracle Nawiązywanie połączenia z bazą danych Używanie metody Local Naming Używanie metody Easy Connect Wykonywanie poleceń SQL względem bazy danych Pobieranie i wyświetlanie wyników Podsumowanie Rozdział 2. Połączenie PHP i Oracle Przedstawienie rozszerzenia PHP OCI8 Dlaczego warto używać rozszerzenia OCI8? Przetwarzanie poleceń za pomocą rozszerzenia OCI8 Nawiązywanie połączenia z Oracle za pomocą rozszerzenia OCI8 Definiowanie ciągu tekstowego połączenia Funkcje rozszerzenia OCI8, które służą do nawiązywania połączenia z Oracle Analizowanie i wykonywanie poleceń SQL za pomocą rozszerzenia OCI8 Przygotowywanie poleceń SQL do wykonania Używanie zmiennych wiązanych Wykonywanie poleceń SQL Obsługa błędów Używanie funkcji oci_error() Używanie funkcji trigger_error() Używanie wyjątków Pobieranie wyników za pomocą funkcji rozszerzenia OCI8 Funkcje rozszerzenia OCI8, które służą do pobierania wyników Pobieranie kolejnego rekordu Pobranie wszystkich rekordów Alternatywy dla rozszerzenia PHP OCI8 Używanie PEAR DB Używanie ADOdb Używanie PDO Tworzenie własnej biblioteki na bazie rozszerzenia OCI8 Podsumowanie Rozdział 3. Przetwarzanie danych Implementacja logiki biznesowej aplikacji PHP/Oracle Kiedy przenosić dane do miejsca działania procesu przetwarzania? Zalety przeniesienia procesu przetwarzania danych do samych danych Sposoby implementacji logiki biznesowej wewnątrz bazy danych Współpraca między komponentami implementującymi logikę biznesową 31 31 32 34 35 37 40 40 41 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 4 Spis treści Używanie skomplikowanych poleceń SQL Używanie funkcji Oracle SQL w zapytaniach Funkcje Oracle SQL kontra przetwarzanie danych w PHP Funkcje agregujące Klauzula GROUP BY Używanie złączeń Wykorzystanie zalet widoków Kluczowe korzyści płynące z używania widoków Ukrywanie złożoności danych za pomocą widoków Używanie klauzuli WHERE Używanie podprogramów składowanych Czym są podprogramy składowane? Zalety podprogramów składowanych Przykład użycia podprogramu składowanego Tworzenie podprogramów składowanych Wywoływanie podprogramów składowanych z poziomu PHP Używanie wyzwalaczy Tworzenie wyzwalaczy Wywoływanie wyzwalaczy Wywoływanie procedur składowanych z poziomu wyzwalacza Podsumowanie Rozdział 4. Transakcje Ogólny opis transakcji Czym jest transakcja? Czym są reguły ACID? W jaki sposób transakcje działają w Oracle? Używanie 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 Używanie wyzwalaczy Wycofanie na poziomie polecenia Rozważania dotyczące izolacji transakcji Którą funkcję rozszerzenia OCI8 służącą do nawiązywania połączenia należy wybrać? Kwestie związane z współbieżnym uaktualnianiem Kwestie związane z nakładaniem blokad Utracone uaktualnienia Transakcje autonomiczne Podsumowanie Rozdział 5. Podejście zorientowane obiektowo Implementacja klas PHP, które pozwalają na współpracę z Oracle Bloki budulcowe aplikacji Tworzenie zupełnie od początku własnej klasy PHP Testowanie nowo utworzonej klasy Wykorzystanie zalet funkcji programowania zorientowanego obiektowo w PHP 5 76 76 77 79 80 80 83 83 84 85 87 87 89 90 94 95 97 98 99 99 100 103 104 104 105 106 107 110 113 113 119 119 120 123 123 127 127 129 132 135 137 138 138 139 141 142 5 Spis treści Funkcjonalność i implementacja Ponowne używanie kodu Obsługa wyjątków Modyfikacja istniejącej klasy w celu użycia wyjątków Rozróżnienie między odmiennymi rodzajami błędów Czy wyjątki koniecznie oznaczają błędy? Rozszerzanie istniejących klas Używanie klas standardowych Pakiet PEAR::Auth w działaniu Zabezpieczanie stron za pomocą PEAR::Auth Dostosowanie klas standardowych do własnych potrzeb Dostosowanie do własnych potrzeb PEAR::Auth Budowanie mniejszego kodu klienta Oddziaływania między obiektami Kompozycja Agregacja Komunikacja bazująca na zdarzeniach Używanie właściwości obiektowych Oracle Używanie typów obiektowych w Oracle Implementacja logiki biznesowej za pomocą metod obiektów Oracle Używanie obiektów Oracle w celu uproszczenia tworzenia aplikacji Podsumowanie Rozdział 6. Bezpieczeństwo Zabezpieczanie aplikacji PHP/Oracle Uwierzytelnianie użytkowników Oddzielenie zarządzania bezpieczeństwem od danych Używanie dwóch schematów bazy danych w celu zwiększenia bezpieczeństwa Używanie trzech schematów bazy danych w celu zwiększenia bezpieczeństwa Używanie pakietów PL/SQL i funkcji tabelarycznych w celu zapewnienia bezpiecznego dostępu do danych bazy danych Używanie atrybutu ROWTYPE Budowanie własnego magazynu dla klasy PEAR::Auth Testowanie systemu uwierzytelniania Przeprowadzanie uwierzytelniania na podstawie tożsamości użytkownika Używanie sesji do przechowywania informacji o uwierzytelnionym użytkownika Przechowywanie informacji o użytkowniku w zmiennych pakietowych Ochrona zasobów na podstawie informacji dotyczących uwierzytelnionego użytkownika Używanie skrótów Tworzenie skrótów haseł Modyfikacja systemu uwierzytelniania w celu przeprowadzenia operacji tworzenia skrótu Implementacja dokładnej kontroli dostępu za pomocą widoków bazy danych Implementacja bezpieczeństwa na poziomie kolumny za pomocą widoków Maskowanie wartości kolumn zwracanych aplikacji Używanie funkcji DECODE() Implementacja bezpieczeństwa na poziomie rekordu za pomocą widoków Bezpieczeństwo na poziomie rekordu przy użyciu funkcji VPD Podsumowanie 6 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 treści Rozdział 7. Buforowanie Buforowanie danych za pomocą Oracle i PHP Buforowanie zapytań w serwerze bazy danych Przetwarzanie poleceń SQL Stosowanie zmiennych wiązanych w celu zwiększenia prawdopodobieństwa użycia bufora puli współdzielonej Używanie kontekstu Oracle podczas buforowania Tworzenie kontekstu globalnego aplikacji Manipulowanie danymi znajdującymi się w kontekście globalnym Zerowanie wartości w kontekście globalnym Mechanizmy buforowania dostępne w PHP Wybór strategii buforowania Wywoływanie funkcji buforowania za pomocą pakietu PEAR::Cache_Lite Uaktualnianie buforowanych danych Implementacja buforowania bazującego na powiadamianiu Używanie funkcji bazy danych powiadamiania o zmianach Kontrola komunikatów powiadamiania Budowanie procedury PL/SQL, która wysyła powiadomienia serwerowi WWW Przeprowadzenie kroków konfiguracyjnych wymaganych przez mechanizm powiadamiania Budowa uchwytu powiadamiania Utworzenie zapytania rejestrującego dla uchwytu powiadamiania Szybki test Implementacja buforowania bazującego na powiadomieniach za pomocą PEAR::Cache_Lite Podsumowanie Rozdział 8. Aplikacje bazujące na XML-u Przetwarzanie danych XML w aplikacjach PHP/Oracle Przetwarzanie danych XML za pomocą PHP 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 wewnątrz bazy danych Używanie funkcji generowania SQL/XML w Oracle Przeniesienie całego procesu przetwarzania danych XML do bazy danych Przechowywanie danych XML w bazie danych Przeprowadzanie transformacji XSLT wewnątrz bazy danych Budowanie aplikacji PHP na podstawie Oracle XML DB Używanie bazy danych Oracle do przechowywania, modyfikowania i pobierania danych XML Dostępne opcje przechowywania danych XML w bazie danych Oracle Używanie XMLType do obsługi danych XML w bazie danych Używanie schematów XML Pobieranie danych XML Uzyskanie dostępu do danych relacyjnych za pomocą widoków XMLType Używanie widoków XMLType Tworzenie widoków XMLType bazujących na schemacie XML Przeprowadzanie operacji DML w widoku XMLType bazującym na schemacie XML 219 220 220 220 222 224 226 228 232 236 236 237 240 242 244 244 245 246 247 249 250 251 253 255 256 256 257 259 260 265 265 268 269 271 272 273 273 275 277 281 285 285 286 289 7 Spis treści Używanie repozytorium Oracle XML DB Manipulowanie zasobami repozytorium za pomocą kodu PL/SQL Uzyskanie dostępu do zasobów repozytorium za pomocą SQL Wykorzystanie zalet standardowych protokołów internetowych Obsługa transakcji Pobieranie danych za pomocą Oracle XQuery Używanie silnika XQuery do budowania danych XML na podstawie danych relacyjnych Rozłożenie danych XML na postać danych relacyjnych Podsumowanie 293 294 294 295 297 298 299 301 302 Rozdział 9. Usługi sieciowe Tworzenie schematu XML przeznaczonego do weryfikacji nadchodzących dokumentów Generowanie unikalnych identyfikatorów dla przekazywanych dokumentów Tworzenie podprogramów PL/SQL implementujących logikę biznesową usługi sieciowej Komunikacja za pomocą SOAP Co jest wymagane do zbudowania usługi sieciowej SOAP? Budowanie usługi sieciowej SOAP na podstawie aplikacji PHP/Oracle Budowanie logiki biznesowej usługi sieciowej wewnątrz bazy danych 303 Udostępnienie aplikacji PHP/Oracle jako usługi sieciowej za pomocą rozszerzenia PHP SOAP 304 304 305 307 308 308 311 313 317 319 322 323 326 327 329 330 332 333 Budowanie uchwytu klasy PHP Używanie WSDL Tworzenie serwera SOAP za pomocą rozszerzenia PHP SOAP Budowanie klienta SOAP w celu przetestowania serwera SOAP Bezpieczeństwo Implementacja logiki autoryzacji wewnątrz 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 działania Projekt aplikacji monitorującej opartej na Ajaksie/PHP/Oracle Rozwiązanie oparte na Ajaksie Tworzenie struktur danych Tworzenie skryptu PHP przetwarzającego żądania Ajaksa Używanie obiektu JavaScript — XMLHttpRequest Złożenie aplikacji w całość Użycie pamięci podręcznej w celu zwiększenia szybkości pracy aplikacji Implementacja rozwiązań Master/Detail z użyciem metodologii Ajax Projektowanie rozwiązania Master/Detail wykorzystującego Ajaksa Opis działania przykładowej aplikacji Tworzenie struktur danych Generowanie kodu HTML za pomocą Oracle XQuery Wysyłanie żądań POST za pomocą Ajaksa Tworzenie stylów CSS Złożenie aplikacji w całość Podsumowanie 8 335 336 336 337 339 339 340 341 345 347 348 348 349 351 353 354 356 357 358 Spis treści Dodatek A Instalacja oprogramowania PHP i Oracle Instalacja oprogramowania Oracle Database Instalacja wydań Oracle Database Enterprise/Standard Instalacja wydania Oracle Database Express Edition 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 między Oracle i PHP Biblioteki Oracle Instant Client Włączenie rozszerzenia OCI8 w istniejącej instalacji PHP Instalacja narzędzia 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 359 360 360 363 363 365 365 367 367 368 369 369 369 371 372 373 373 374 375 9 4 Transakcje Aby uzyskać pewność, że używane dane zawsze będą prawidłowe, należy stosować transakcje. W skrócie: dostarczają one mechanizm pozwalający na bezpieczne modyfikowanie danych prze- chowywanych w bazie danych poprzez przeniesienie bazy danych z jednego spójnego stanu do kolejnego. Klasycznym przykładem wykorzystania transakcji jest operacja bankowa, taka jak przelew środków pieniężnych z jednego konta bankowego na inne. Załóżmy, że zachodzi potrzeba przelania środków pieniężnych z konta oszczędnościowego na konto bieżące. W celu wyko- nania tej operacji trzeba będzie przeprowadzić przynajmniej dwa kroki: zmniejszyć wartości środków na koncie oszczędnościowym i zwiększyć wartość środków na koncie bieżącym. Oczywiste jest, że w tego rodzaju sytuacji konieczne będzie potraktowanie obu operacji jako pojedynczej, aby zachować saldo między kontami. Dlatego też żadna z wymienionych operacji nie może zostać przeprowadzona oddzielnie — muszą być zakończone obie lub żadna z nich — programista musi zagwarantować, że albo obie operacje zakończą się powodzeniem, albo żadna z nich nie będzie przeprowadzona. W takiej sytuacji doskonałym rozwiązaniem jest za- stosowanie transakcji. W rozdziale zostały omówione różne mechanizmy, które mogą być użyte do przeprowadzania transakcji za pomocą technologii PHP i Oracle. Zaczniemy od ogólnego omówienia transakcji, ponieważ te informacje są bardzo ważne w celu dokładnego zrozumienia sposobu działania transakcji. Następnie zostały przedstawione szczegółowy dotyczące stosowania na różne spo- soby transakcji w aplikacjach PHP/Oracle. PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa Ogólny opis transakcji Przed rozpoczęciem budowania własnych aplikacji PHP/Oracle wykorzystujących transakcje należy zapoznać się z podstawowymi informacjami, które dotyczą transakcji, i przekonać się, jak mogą być przeprowadzane z poziomu PHP i Oracle. W podrozdziale zaprezentowano ogólny opis transakcji oraz poruszono następujące zagadnienia: (cid:81) Czym są transakcje i kiedy programista może chcieć je stosować? (cid:81) Jak przeprowadzać transakcje za pomocą PHP i Oracle? (cid:81) Jak zorganizować aplikację PHP/Oracle, aby efektywnie kontrolować transakcje? Ponieważ wymienione powyżej zagadnienia najlepiej można zrozumieć za pomocą przykła- dów, w podrozdziale znajdzie się kilka prostych przykładów pokazujących możliwy sposób wykorzystania transakcji w aplikacjach PHP/Oracle. Czym jest transakcja? Ogólnie rzecz biorąc, transakcja jest czynnością lub serią czynności, które przenoszą system z jednego stanu spójności do kolejnego. Z punktu widzenia programisty budującego aplikacje oparte na bazie danych transakcja może być uznawana za niewidzialny zestaw operacji, które przenoszą bazę danych z jednego stanu spójności do kolejnego. Transakcja jest jednostką logiczną pracy, zawierającą jedno lub większą liczbę poleceń SQL, które mogą być w całości albo zatwierdzone, albo wycofane. Oznacza to, że wszystkie polecenia SQL zawarte w transakcji muszą być z powodzeniem za- kończone, aby cała transakcja mogła zostać zatwierdzona, dzięki czemu zmiany przeprowa- dzone przez wszystkie operacje DML zostają trwale przeprowadzone. Graficznie zostało to pokazane na rysunku 4.1. Rysunek 4.1. Graficzne przedstawienie sposobu działania transakcji 104 Rozdział 4. • Transakcje Jak można zobaczyć na powyższym rysunku, polecenia SQL składające się na transakcję przeno- szą dane, na których operują z jednego stanu spójności do kolejnego. Transakcja musi zostać zatwierdzona, aby wprowadzone przez nią zmiany zostały zastosowane w bazie danych i tym samym przeniosły dane do kolejnego stanu spójności. W przeciwnym razie wszystkie polece- nia SQL wykonane przez transakcję zostaną wycofane, a dane pozostaną w stanie, w którym znajdowały się w chwili rozpoczęcia transakcji. Jeżeli w trakcie wykonywania transakcji wystąpi błąd serwera, na przykład awaria sprzętu komputerowego, efekty transakcji zostaną automatycznie wycofane. Jednak w pewnych sytu- acjach programista może chcieć ręcznie wycofać ukończoną (ale jeszcze nie zatwierdzoną) transakcję, w zależności od ustalonego warunku. Taka sytuacja została pokazana graficznie na rysunku 4.2. Rysunek 4.2. Graficzne przedstawienie warunkowego zatwierdzenia transakcji Jak widać na powyższym rysunku, po zakończeniu wykonywania wszystkich poleceń transak- cji programista ma możliwość albo jej zatwierdzenia, albo wycofania. Czym są reguły ACID? ACID to akronim oznaczający Atomicity (niepodzielność), Consistency (spójność), Isolation (izolacja) oraz Durability (trwałość). Każdy system zarządzania bazą danych obsługujący transakcje musi spełniać powyższe cechy charakterystyczne. Ich podsumowanie znalazło się w pierwszej tabeli na następnej stronie. Baza danych Oracle obsługuje wszystkie właściwości ACID wymienione w powyższej tabeli. Dlatego podczas budowania aplikacji transakcyjnych na Oracle nie trzeba projektować wła- snych schematów gwarantujących spójność i integralność danych. Zamiast tego zawsze lep- szym rozwiązaniem będzie wykorzystanie transakcji Oracle i zrzucenie obsługi tego rodzaju problemów na bazę danych. 105 PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa Właściwość Niepodzielność Spójność Izolacja Trwałość Opis Transakcja stanowi niepodzielną jednostkę pracy. Oznacza to, że albo wszystkie operacje w ramach transakcji zostaną wykonane, albo nie będzie wykonana żadna z nich. Transakcja przenosi bazę danych z jednego stanu spójności do kolejnego. Oznacza to, że podczas przeprowadzania transakcji nie mogą być złamane żadne czynniki wpływające na spójność bazy danych. Jeżeli transakcja złamie jakiekolwiek reguły spójności, zostanie wycofana. Do chwili zatwierdzenia transakcji zmiany wprowadzane przez operacje składające się na transakcję nie powinny być widoczne dla innych, równocześnie przeprowadzanych transakcji. Gdy transakcja zostanie zatwierdzona, wszystkie modyfikacje wprowadzone przez transakcję staną się trwałe i widoczne dla innych transakcji. Trwałość gwarantuje, że jeśli zatwierdzenie transakcji zakończy się powodzeniem, w przypadku awarii systemu nie będą one wycofane. W jaki sposób transakcje działają w Oracle? W podrozdziale zostanie pokrótce przedstawiony ogólny opis działania transakcji w Oracle. Szczegółowe informacje dotyczące sposobu działania transakcji w bazie danych Oracle można znaleźć w dokumentacji Oracle: w rozdziale „Transaction Management” w podręczniku użyt- kownika Oracle Database Concepts. W Oracle transakcja nie rozpoczyna się jawnie, lecz niejawnie podczas uruchamiania pierw- szego wykonywalnego polecenia SQL. Jednak istnieje kilka sytuacji powodujących zakończe- nie transakcji. Przedstawiono w poniższej tabeli: Sytuacja Opis Po wydaniu polecenia COMMIT następuje zakończenie wykonywania bieżącej transakcji. Polecenie powoduje, że zmiany wprowadzone przez polecenia SQL transakcji stają się trwałe. Po wydaniu polecenia ROLLBACK następuje zakończenie wykonywania bieżącej transakcji. Polecenie to powoduje, że zmiany wprowadzone przez polecenia SQL transakcji zostają wycofane. Jeżeli zostanie wydane polecenie DDL, Oracle w pierwszej kolejności zatwierdzi bieżącą transakcję, a następnie wykona i zatwierdzi polecenie DDL w nowej transakcji, która składa się z pojedynczego polecenia. Kiedy połączenie zostanie zamknięte, Oracle automatycznie zatwierdzi bieżącą transakcję w tym połączeniu. Jeżeli wykonywanie programu zostanie nieprawidłowo przerwane, Oracle automatycznie wycofa bieżącą transakcję. Wydanie polecenia COMMIT Wydanie polecenia ROLLBACK Wydanie polecenia DDL Zamknięcie połączenia Nieprawidłowe przerwanie wykonywania programu 106 Rozdział 4. • Transakcje Jak można się przekonać na podstawie powyższej tabeli, transakcja zawsze będzie albo zatwier- dzona, albo wycofana, niezależnie od tego, czy zostanie wyraźnie zatwierdzona, czy wycofana. Warto jednak zwrócić uwagę, że zawsze dobrą praktyką jest wyraźne zatwierdzanie lub wy- cofywanie transakcji zamiast polegania na zachowaniu domyślnym Oracle. W rzeczywistości zachowanie domyślne aplikacji transakcyjnej może być różne w zależności od narzędzia sto- sowanego przez aplikację do nawiązywania połączenia z bazą danych Oracle. Na przykład jeżeli skrypt PHP współpracuje z bazą danych Oracle za pomocą rozszerzenia OCI8, nie można liczyć na to, że aktywna transakcja w połączeniu zostanie automatycznie zatwierdzona po zamknięciu tego połączenia. W takim przypadku po zamknięciu połączenia lub zakończeniu wykonywania skryptu aktywna transakcja zostanie wycofana. Natomiast jeżeli rozłączenie z bazą danych nastąpi po wydaniu polecenia DISCONNECT z poziomu narzędzia SQL*Plus lub nastąpi połączenie z bazą jako inny użytkownik używający polecenia CONNECT bądź sesja SQL*Plus zostanie zamknięta w wyniku wydania polecenia EXIT, aktywna transakcja w połączeniu będzie zatwierdzona. Aby uniknąć nieoczekiwanego zachowania w aplikacji, zawsze dobrze jest wyraźnie zatwierdzać bądź wycofywać transakcje, zamiast polegać na zachowaniu domyślnym aplikacji transakcyjnej. Używanie transakcji w aplikacjach PHP/Oracle Jak wspomniano w poprzednim podrozdziale, w Oracle można wyraźnie albo zatwierdzić, albo wycofać transakcję, używając polecenia odpowiednio COMMIT lub ROLLBACK. W celu wykonania po- wyższych poleceń z poziomu kodu PHP nie trzeba używać funkcji oci_parse() i oci_execute(), jak podczas wykonywania innych poleceń SQL, takich jak SELECT lub INSERT. Zamiast tego używa się funkcji rozszerzenia OCI8 o nazwach oci_commit() i oci_rollback(). Przedstawiony poniżej skrypt PHP demonstruje sposób wyraźnego zatwierdzenia lub wyco- fania transakcji z poziomu kodu PHP podczas używania operacji DML. Zadaniem skryptu jest próba uaktualnienia rekordów tabeli employees, reprezentujących pracowników, których identyfikator stanowiska wynosi ST_MAN (menedżer magazynu). Uaktualnienie polega na zwiększeniu wysokości pensji o 10 . Jeżeli uaktualnienie jednego lub większej liczby rekordów zakończy się niepowodzeniem, cała transakcja zostanie wycofana, a uaktualnionym polom pensji będą przywrócone ich wartości początkowe. Cały proces podsumowują poniższe kroki: (cid:81) Krok 1.: wykonanie zapytania względem tabeli employees w celu uzyskania liczby rekordów przedstawiających pracowników na wskazanym stanowisku (menedżerów magazynu). (cid:81) Krok 2.: rozpoczęcie transakcji i wykonanie operacji UPDATE względem tabeli employees w celu przeprowadzenia próby zwiększenia pensji menedżerów magazynu o 10 . 107 PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa (cid:81) Krok 3.: wycofanie transakcji, jeśli liczba rekordów zmodyfikowanych przez operację UPDATE będzie mniejsza niż liczba rekordów przedstawiających menedżerów. W przeciwnym razie transakcja zostanie zatwierdzona. Teraz warto zapoznać się z kodem źródłowym skryptu, aby przekonać się, jak powyższe 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 można nawiązać połączenia 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 zakończyło 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 zakończyła się niepowodzeniem: . $err[ message ], E_USER_ERROR); } $updrows = oci_num_rows($stmt); print Próba uaktualnienia .$numrows. rekordów. br / ; print Udało się uaktualnić .$updrows. rekordów. br / ; if ($updrows $numrows) { if (!oci_rollback($dbConn)) { $err = oci_error($dbConn); trigger_error( Nie udało się wycofać transakcji: .$err[ message ], E_USER_ERROR); } print Transakcja została wycofana. ; } else { if (!oci_commit($dbConn)) { $err = oci_error($dbConn); 108 Rozdział 4. • Transakcje trigger_error( Nie udało się zatwierdzić transakcji: .$err[ message ], E_USER_ERROR); } print Transakcja została zatwierdzona. ; } ? W powyższym skrypcie zdefiniowano zapytanie zwracające liczbę rekordów, które przedsta- wiają pracowników zatrudnionych jako menedżerowie magazynu. W zapytaniu użyto funkcji count() w celu obliczenia liczby rekordów spełniających kryteria zdefiniowane w klauzuli WHERE zapytania. W omawianym przypadku wartością zwrotną funkcji count(*) jest liczba rekor- dów reprezentujących pracowników, dla których wartość pola job_id wynosi ST_MAN. W skrypcie liczba rekordów przedstawiających menedżerów magazynu jest pobierana z bufo- ra wynikowego za pomocą połączenia funkcji oci_fetch() i oci_result(). Nie trzeba w tym przypadku stosować pętli, ponieważ zapytanie zwraca tylko jeden rekord zawierający poje- dyncze pole o nazwie num_rows. Następnie wykonywane jest zapytanie uaktualniające kolumnę salary tabeli employees. Uak- tualnienie polega na zwiększeniu pensji menedżerów magazynu o 10 . Zapytanie uaktualnia wysokość pensji tylko wtedy, gdy nowa wysokość pensji będzie mieściła się między minimal- ną i maksymalną wysokością pensji ustalonymi dla menedżerów magazynu i zdefiniowanymi w tabeli jobs. W omawianym przykładzie polecenie UPDATE jest wykonywane w trybie wykonywania OCI_ (cid:180)DEFAULT. W ten sposób następuje rozpoczęcie transakcji, która pozwala programiście w dalszej części skryptu na wyraźne zatwierdzenie lub wycofanie zmian wprowadzonych przez polece- nie UPDATE. Interesującą kwestią, na którą warto zwrócić uwagę, jest fakt, że domyślny tryb wykonywania to OCI_COMMIT_ON_SUCCESS, w którym polecenie jest zatwierdzane automatycz- nie, jeśli jego wykonywanie zakończy się powodzeniem. Według dokumentacji Oracle aplikacja zawsze powinna wyraźnie zatwierdzać bądź wycofywać transak- cję przed zakończeniem działania programu. Jednak podczas używania 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, jeśli jego wykonanie zakończy się powodzeniem (czyli w sytuacji podobnej do wyraźnego zatwierdzenia natychmiast po wykonaniu polecenia). Jeżeli błąd serwera uniemożliwi zakończenie powodzeniem wykonywania polecenia SQL, Oracle automatycznie wycofa wszystkie zmiany wprowadzone przez nie. W omawianym skrypcie funkcja oci_num_rows() jest wywoływana w celu uzyskania liczby re- kordów zmodyfikowanych przez operację UPDATE. Po poznaniu liczby rekordów przedstawia- jących menedżerów magazynu oraz liczby faktycznie uaktualnionych można porównać te wartości i sprawdzić, czy są identyczne. 109 PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa W powyższym skrypcie wycofanie transakcji następuje, gdy liczba uaktualnionych rekordów jest mniejsza niż całkowita liczba rekordów przedstawiających menedżerów magazynu. Ma to sens, ponieważ niedopuszczalna jest sytuacja, w której uaktualnione zostaną rekordy tylko niektórych menedżerów magazynu. Możliwość wycofania zmian w przypadku wystąpienia takiej sytuacji ma znaczenie krytyczne — pozwala wówczas na użycie innego skryptu, który będzie mógł prawidłowo uaktualnić wszystkie rekordy przedstawiające menedżerów magazynu. Na przykład w rzeczywistej sytu- acji prawdopodobnie pożądanym rozwiązaniem będzie zwiększenie pensji menedżera maga- zynu do maksymalnej dopuszczalnej wysokości, jeśli jej podwyżka o 10 przekroczy to do- zwolone maksimum. Jeżeli operacja UPDATE zmodyfikuje wszystkie rekordy przedstawiające menedżerów magazy- nu, transakcję można zatwierdzić za pomocą funkcji oci_commit(), dzięki czemu wprowadzo- ne zmiany będą trwałe. Innym elementem, na który warto zwrócić uwagę w omawianym skrypcie, jest użyty mecha- nizm obsługi błędów. Jeżeli w trakcie wykonywania funkcji oci_rollback() lub oci_commit() wystąpi błąd, identyfikator połączenia będzie przekazany funkcji oci_error(), która z kolei zwróci komunikat błędu opisujący powstały błąd. Strukturyzacja aplikacji PHP/Oracle w celu nadzorowania transakcji Jak Czytelnik może przypomnieć sobie z lektury rozdziału 3., ogólnie rzecz biorąc, dobrym pomysłem jest umieszczenie wewnątrz bazy danych kluczowej logiki biznesowej aplikacji PHP/Oracle. Padło tam też również stwierdzenie, że w prostych przypadkach nie trzeba na- wet tworzyć kodu PL/SQL w celu przeniesienia do bazy danych procesu przetwarzania da- nych. Zamiast tego można zaprojektować skomplikowane zapytania SQL, które po wydaniu będą nakazywały serwerowi bazy danych przeprowadzenie wszystkich wymaganych operacji przetwarzania danych. Wracając do przykładu omówionego w poprzednim podrozdziale: istnieje możliwość modyfi- kacji użytego w nim polecenia UPDATE w taki sposób, aby rekordy przedstawiające menedże- rów magazynu były uaktualniane tylko wtedy, gdy nowa wysokość pensji każdego menedżera nadal będzie znajdowała się między wartością minimalną i maksymalną dla tego stanowiska. Wymienione wartości są zdefiniowane w tabeli jobs. Taka modyfikacja wyeliminuje potrzebę wykonywania oddzielnego zapytania, które zwraca liczbę rekordów spełniających powyższy warunek. W ten sposób nastąpi zmniejszenie ilości kodu koniecznego do napisania w celu implementacji żądanego zachowania funkcji. W skrócie: nowa wersja polecenia UPDATE łączy w ramach pojedynczego polecenia wszystkie trzy kroki wymienione na początku poprzedniego podrozdziału. Nie trzeba nawet wyraźnie 110 Rozdział 4. • Transakcje zatwierdzać bądź wycofywać operacji UPDATE. Zamiast tego polecenie UPDATE można wydać w trybie OCI_COMMIT_ON_SUCCESS, który gwarantuje, że operacja zostanie automatycznie zatwier- dzona, jeśli jej wykonanie zakończy się powodzeniem, a w przeciwnym razie — wycofana. Przedstawiony poniżej skrypt prezentuje w działaniu nową wersję polecenia UPDATE: ?php // Plik: transQuery.php. if(!$dbConn = oci_connect( hr , hr , //localhost/orcl )) { $err = oci_error(); trigger_error( Nie można nawiązać połączenia 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 zakończyło się niepowodzeniem: . $err[ message ], E_USER_ERROR); }; $updrows = oci_num_rows($stmt); if ($updrows 0) { print Transakcja została zatwierdzona. ; } else { print Transakcja została wycofana. ; } ? W powyższym fragmencie kodu zdefiniowano polecenie UPDATE, które spowoduje uaktualnie- nie wszystkich rekordów reprezentujących menedżerów magazynu poprzez zwiększenie wy- sokości ich pensji o 10 , pod warunkiem że żadna z nowych wartości pensji nie przekroczy maksymalnej pensji menedżera magazynu zdefiniowanej w tabeli jobs. Jeżeli chociaż jedna pensja przekroczy wartość maksymalną, polecenie UPDATE nie uaktualni żadnych rekordów. Aby uzyskać taki sposób działania, zamiast podawania tabeli employees w klauzuli polecenia UPDATE użyte zostało polecenie SELECT, którego wartością zwrotną są albo wszystkie rekordy 111 PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa tabeli employees, albo żaden z nich. Zależy to od tego, czy wszystkie rekordy spełniające wa- runek zdefiniowany w klauzuli WHERE polecenia UPDATE (w omawianym przypadku będą to wszystkie rekordy reprezentujące menedżerów magazynu) mogą być uaktualnione w taki spo- sób, aby każda nowa wysokość pensji nie przekraczała wartości maksymalnej pensji dla tego stanowiska. To polecenie SELECT jest uznawane za widok wewnętrzny. W przeciwieństwie do zwykłych widoków omówionych w podrozdziale „Wykorzystanie zalet widoków”, znajdującym się w rozdziale 3., widoki wewnętrzne nie są obiektami schematu bazy danych, ale podzapytaniami, które mogą być stosowane jedynie w ramach zawierających je poleceń za pomocą aliasów. W omawianym przykładzie zastosowanie w poleceniu UPDATE wewnętrznego widoku emp po- woduje wyeliminowanie potrzeby wykonywania oddzielnego zapytania zwracającego liczbę rekordów reprezentujących menedżerów magazynu, a następnie sprawdzającego, czy otrzy- mana liczba jest równa liczbie rekordów faktycznie zmodyfikowanych przez polecenie UPDATE. Teraz skrypt wykonuje tylko pojedyncze zapytanie SQL, dzięki czemu wyraźnie skraca czas wykonywania skryptu. Omówiony skrypt jest dobrym przykładem pokazującym korzyści, jakie można odnieść po przeniesieniu kluczowej logiki biznesowej aplikacji PHP/Oracle z PHP do bazy danych Oracle. Tu zamiast używania dwóch oddzielnych poleceń i analizowania ich wyników w PHP zastosowane zostało tylko jedno pole- cenie SQL, które powoduje, że przetwarzanie danych zachodzi całkowicie w serwerze bazy danych. Warto także zwrócić uwagę na użyty w skrypcie sposób wiązania zmiennych. Zmienna PHP jobno jest dowiązywana do znacznika jobid użytego w poleceniu UPDATE. Interesujący jest fakt, że znacznik zmiennej wiązanej jobid pojawia się w poleceniu częściej niż tylko jednokrotnie. Inaczej niż w poprzednim przykładzie, w którym polecenie UPDATE było wykonywane w try- bie OCI_DEFAULT, wyraźnie rozpoczynającym transakcję, nowa wersja skryptu wykonuje pole- cenie w trybie OCI_COMMIT_ON_SUCCESS. Operacja UPDATE jest więc automatycznie zatwierdza- na, jeśli jej wykonanie zakończy się powodzeniem. Jak wcześniej wspomniano, OCI_COMMIT_ON_SUCCESS jest trybem domyślnym wykonywania polece- nia. Oznacza to, że nie trzeba wyraźnie go określać podczas wywoływania funkcji oci_execute(). W omawianym przykładzie został wyraźnie umieszczony w kodzie źródłowym, aby zwrócić na to uwagę. W poprzednim przykładzie nadal używano funkcji oci_num_rows() w celu pobrania liczby re- kordów zmodyfikowanych przez polecenie UPDATE. Jednak tym razem nie trzeba porównywać tej liczby z całkowitą liczbą rekordów reprezentujących menedżerów magazynu, jak to miało miejsce w przypadku poprzedniego skryptu. Wszystko, co trzeba zrobić, to prostu sprawdzić, czy liczba rekordów zmodyfikowanych przez polecenie UPDATE jest większa niż 0. 112 Rozdział 4. • Transakcje Jeżeli liczba uaktualnionych rekordów jest większa niż 0, oznacza to, że operacja UPDATE zmo- dyfikowała wszystkie rekordy reprezentujące menedżerów magazynu i została z powodze- niem zatwierdzona. W takim przypadku należy wyświetlić użytkownikowi komunikat infor- mujący o zatwierdzeniu transakcji. Jeżeli liczba uaktualnionych rekordów wynosi 0, oznacza to, że operacja UPDATE nie zmodyfi- kowała żadnych rekordów. W takim przypadku należy wyświetlić użytkownikowi komunikat informujący o wycofaniu transakcji. Jednak w rzeczywistości transakcja jest zatwierdzona, ale żaden rekord nie został zmodyfikowany przez operację UPDATE. Tworzenie kodu transakcyjnego Dotychczas przedstawiono kilka prostych przykładów pokazujących podstawy działania transakcji Oracle z PHP. W podrozdziale zostaną zaprezentowane bardziej skomplikowane przykłady stosowania transakcji w aplikacjach PHP/Oracle. Nadzorowanie transakcji z poziomu PHP Jak Czytelnik dowiedział się z przykładów omówionych we wcześniejszej części rozdziału, funkcja oci_execute() pozwala na wykonywanie polecenia SQL w dwóch trybach — OCI_COMMIT_ (cid:180)ON_SUCCESS oraz OCI_DEFAULT. Podczas gdy stosowanie trybu OCI_COMMIT_ON_SUCCESS powoduje, że polecenia są automatycz- nie zatwierdzane, użycie trybu OCI_DEFAULT wymaga wyraźnego wywołania funkcji oci_commit() w celu zatwierdzenia transakcji lub oci_rollback(), aby ją wycofać. Jednak warto zwrócić uwagę, że gdy polecenie jest wykonywane w trybie OCI_DEFAULT, utwo- rzona wówczas transakcja nadal może być zatwierdzona bez wywoływania funkcji oci_commit(). W tym celu późniejsze polecenie należy wykonać w trybie OCI_COMMIT_ON_SUCCESS. Powyższa technika może być zastosowana podczas grupowania dwóch lub większej liczby poleceń w pojedynczą transakcję. Aby zagwarantować, że cała transakcja będzie wycofana, kiedy wykonanie jednego z poleceń zakończy się niepowodzeniem lub zostaną uzyskane wy- niki wskazujące na konieczność wycofania transakcji, można po prostu przerwać wykonywa- nie skryptu. W tym celu można wywołać na przykład funkcję trigger_error() wraz ze stałą E_USER_ERROR jako drugim parametrem, a tym samym wycofać transakcję bez potrzeby wy- woływania funkcji oci_rollback(). Czytelnik może się zastanawiać, dlaczego omawiany jest niejawny sposób kończenia transakcji Oracle z poziomu PHP zamiast wyraźnego wywołania funkcji oci_commit() bądź oci_rollback(). W końcu druga z wymienionych funkcji stanowi zalecaną metodę kończenia transakcji. Ogólnie 113 PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa rzecz biorąc, celem tej analizy jest umożliwienie łatwiejszego zrozumienia sposobu działania transakcji Oracle w skryptach PHP, które współdziałają z bazą danych za pomocą rozsze- rzenia OCI8. W przykładzie, który zostanie omówiony poniżej, użyto struktur danych, które zdefiniowano w podrozdziale „Przykład użycia podprogramu składowanego”, znajdującym się w rozdziale 3. Zanim jednak przejdziemy do przykładu, konieczne jest zmodyfikowanie wymienionych struktur danych w przedstawiony poniżej sposób. Te polecenia SQL można wykonać z poziomu na- rzędzia SQL*Plus po nawiązaniu połączenia 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 powyższym bloku kodu powoduje dodanie do tabeli accounts kolumny num_logons typu INT. W nowej kolumnie będzie przechowywana liczba udanych operacji logowania każdego użytkownika. W tym celu gdy uwierzytelnienie użytkownika zakończy się powodzeniem, trzeba będzie zwiększyć liczbę operacji logowania przechowywaną w polu num_logons. Oczywiście, nadal można się obejść bez tej kolumny, wydając względem tabeli logons zapyta- nie podobne do poniższego: SELECT count(*) FROM logons WHERE usr_id= bob ; Jednak wraz ze wzrostem liczby operacji logowania powyższe zapytanie będzie bardzo kosz- towne jak na otrzymanie informacji o liczbie logowań przeprowadzonych przez danego użyt- kownika. Po dodaniu komuny num_logons do tabeli accounts nowej kolumnie należy ustawić wartość początkową wynoszącą 0. Ewentualnie wcześniejsze polecenie ALTER TABLE można było wydać z użyciem klauzuli DEFAULT względem kolumny num_logons, na przykład następująco: ALTER TABLE accounts ADD (num_logons INT DEFAULT 0); W omawianym bloku kodu następuje wyraźne zatwierdzenie transakcji, aby zmiany wprowa- dzone przez operację UPDATE były trwałe. W kolejnym kroku usuwane są wszystkie rekordy tabeli logons. Ten krok jest wymagany, aby zagwarantować prawidłowe wykonanie polecenia check constraint zdefiniowanego w następnym 114 Rozdział 4. • Transakcje kroku. W omawianym przykładzie można pominąć ten krok, jeżeli tabela logons nie zawiera rekordów utworzonych w sobotę lub niedzielę, co umożliwi prawidłowe wykonanie polecenia check constraint zdefiniowanego w kolejnym kroku. W przeciwnym razie podczas próby wyko- nania polecenia ALTER TABLE zostanie wyświetlony następujący komunikat błędu: 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. Wymienio- ne ograniczenie uniemożliwia wstawianie nowych rekordów do tabeli logons w sobotę lub niedzielę. Pozwala to na modyfikację systemu uwierzytelniania w taki sposób, aby uniemożli- wić użytkownikom logowanie się w soboty i niedziele, a tym samym pozwolić na logowanie jedynie w dni robocze. W późniejszym czasie takie ograniczenie zawsze będzie można usunąć poprzez wydanie następującego polecenia: ALTER TABLE logons DROP CONSTRAINT log_time_day; Wróćmy jeszcze do polecenia ALTER TABLE, które przedstawiono powyżej. Warto zwrócić uwagę na użyty 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. Następnie stosowany jest operator NOT IN, który powoduje wykluczenie soboty (Saturday) i niedzieli (Sunday) z listy dozwolonych dni. Należy pamiętać, że baza danych Oracle rozróżnia wielkość liter podczas dopasowania. Dla- tego też jeśli podano Day jako drugi parametr funkcji TO_CHAR(), dni tygodnia na liście znajdują- cej się po prawej stronie operatora NOT IN należy podać jako: Saturday , Sunday . Miałyby one postać SATURDAY , SUNDAY , gdyby drugi parametr funkcji TO_CHAR() został podany jako DAY . Powyższe polecenia powodują przeprowadzenie wszystkich wymaganych modyfikacji struk- tury bazy danych. Po ich wykonaniu można więc przejść do przykładu, którego zadaniem jest zilu- strowanie sposobów tworzenia transakcji poprzez wykonanie polecenia DML w trybie OCI_DEFAULT, a następnie wyraźnego zakończenia tej transakcji po wykonaniu kolejnego polecenia, ale w trybie OCI_COMMIT_ON_SUCCESS. W rzeczywistości oczywiście może zajść potrzeba użycia więcej niż tylko dwóch poleceń w transakcji. W tym celu można wykonać w trybie OCI_DEFAULT wszystkie polecenia (poza ostat- nim), które mają zostać zgrupowane w pojedynczej transakcji, a następnie wykonać ostatnie polecenie w trybie OCI_COMMIT_ON_SUCCESS — transakcja będzie zakończona. Graficzne przedstawienie całego procesu pokazano na rysunku 4.3. Przedstawiony poniżej skrypt prezentuje, w jaki sposób architektura pokazana na rysunku 4.3 może być zaimplementowana w PHP. Warto zauważyć, że w przeciwieństwie do funkcji login(), omówionej w podrozdziale „Przykład użycia podprogramu składowanego”, który znajduje się w rozdziale 3., przedstawiona poniżej 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 omówionego powyżej bloku kodu wartość false, kiedy wstawienie rekordu do tabeli logons zakończy się niepowodzeniem. Ma to sens, ponieważ obecnie nowy rekord jest wstawiany do tabeli logons nie tylko w celu zapisania informacji o logowaniu, ale także sprawdzenia, czy wstawiane dane stosują się do zasad bizneso- wych. Wymienione zasady oznaczają, że do tabeli logons nie może być wstawiony żaden rekord zawierający w kolumnie log_time datę, dla której dniem tygodnia jest sobota bądź niedziela. ?php // Plik: userLoginTrans.php. function login($usr, $pswd) { if(!$rsConnection = oci_connect( usr , usr , //localhost/orcl )) { $err = oci_error(); trigger_error( Nie można nawiązać połączenia 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 zakończyło się niepowodzeniem: . $err[ message ], E_USER_ERROR); } if (!$arr = oci_fetch_array($stmt, OCI_ASSOC)) { print Podano nieprawidłową nazwę użytkownika lub hasło. ; 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 zakończyła 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 zakończyła się niepowodzeniem: . $err[ message ], E_USER_WARNING); if ($err[ code ]== 02290 ){ print Nie można nawiązać połączenia w sobotę lub niedzielę. ; } return false; } print Witaj .$arr[ FULL_NAME ]. br/ ; print Odwiedziłeś nas już .$num_logons. raz(y) ; session_start(); $_SESSION[ user ]=$usr; return true; } ? Jak już wcześniej wspomniano, kolumna num_logons w tabeli accounts przechowuje liczbę zakończonych powodzeniem operacji logowania każdego użytkownika. W skrypcie zdefinio- wano polecenie UPDATE, zwiększające wartość pola num_logons w rekordzie reprezentującym użytkownika, którego dane uwierzytelniające zostały użyte podczas procesu uwierzytelniania. Poprzez wykonanie tego polecenia w trybie OCI_DEFAULT następuje utworzenie nowej transak- cji. Ma to sens, ponieważ wówczas istnieje możliwość wycofania zmian wprowadzonych przez operację UPDATE, jeśli kolejna operacja wstawiania danych do tabeli logons zakończy się nie- powodzeniem. Jeżeli wykonanie operacji UPDATE zakończy się niepowodzeniem, nastąpi opuszczenie funkcji login() i zwrócenie wartości false wywołującemu ją skryptowi. W ten sposób skrypt otrzy- muje informacje, że uwierzytelnienie nie powiodło się. Następnie w omawianym przykładzie zdefiniowane jest polecenie INSERT, które jest wykonywane po zakończonym powodzeniem uwierzytelnieniu użytkownika. Wykonanie go powoduje zwięk- szenie licznika informującego o przeprowadzonej liczbie prawidłowych 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 gwa- rantuje, że transakcja zostanie zatwierdzona w przypadku powodzenia operacji, a w przeciw- nym razie wycofana. Oznacza to, że zmiany wprowadzone zarówno przez polecenie INSERT, jak i UPDATE albo staną się trwałe, albo będą wycofane. Jak Czytelnik zapewne pamięta, wartością zwrotną funkcji oci_error() jest tablica asocjacyj- na dwóch elementów. Pierwszy z nich — code — zawiera kod błędu Oracle, a drugi, message — komunikat błędu opisujący ten błąd. W omawianym przykładzie następuje sprawdzenie, czy kod błędu Oracle jest równy 02290. Jeżeli tak, oznacza to wystąpienie błędu związanego ze złamaniem nałożonego ograniczenia. Ponieważ w tabeli logons zdefiniowano tylko jedno ograniczenie (uniemożliwiające wstawiania nowych rekordów do tabeli logons w soboty i nie- dziele), można poinformować użytkownika o braku możliwości uzyskania połączenia w sobotę bądź niedzielę. Jeżeli w omawianym skrypcie wykonanie polecenia INSERT zakończy się niepowodzeniem, nastąpi zakończenie działania funkcji login() wraz z wartością zwrotną false. Wskazuje to wywołującemu ją skryptowi, że uwierzytelnienie nie powiodło się. W przypadku uwierzytelnienia zakończonego powodzeniem można podjąć odpowiednie działania, na przykład wyświetlić komunikat powitania i utworzyć nową sesję. Aby teraz zobaczyć w działaniu nowo utworzoną funkcję login(), można wykorzystać poniż- szy 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 przedstawiająca nazwę konta nie została ustawiona. . /p ; } }else { print p . Uwierzytelnienie zakończyło się niepowodzeniem . /p ; } ? Jeżeli przedstawiony powyżej skrypt testLoginTrans.php zostanie uruchomiony w sobotę lub niedzielę, spowoduje wyświetlenie następującego komunikatu: Nie można nawiązać połączenia w sobotę lub niedzielę. Uwierzytelnienie zakończyło się niepowodzeniem. Jednak uruchomienie skryptu w dniu roboczym spowoduje wygenerowanie następujących danych wyjściowych: 118 Rozdział 4. • Transakcje Witaj Bob Robinson Odwiedziłeś nas już 1 raz(y) Twoja nazwa konta: bob Każde kolejne uruchomienie skryptu testLoginTrans.php w dniu roboczym spowoduje zwięk- szenie licznika odwiedzin strony przez użytkownika Bob Robinson. Jednak wykonanie tego skryptu w sobotę lub niedzielę nie powoduje zwiększenia wartości licznika. Powyższy test udowadnia, że wszystko działa zgodnie z założeniami. Przenoszenie kodu transakcyjnego do bazy danych Teraz, gdy Czytelnik dysponuje już działającym rozwiązaniem transakcyjnym zaimplemento- wanym przede wszystkim w PHP, warto zastanowić się, w jaki sposób można zmniejszyć ilość kodu PHP poprzez przeniesienie części logiki biznesowej aplikacji do bazy danych. Używanie wyzwalaczy Pracę można rozpocząć od zdefiniowania wyzwalacza BEFORE INSERT, obejmującego tabelę logons, który będzie automatycznie uaktualniał tabelę accounts poprzez zwiększanie wartości pola num_logons w odpowiednim rekordzie. W ten sposób zostanie wyeliminowana potrzeba wykonywania tej operacji UPDATE z poziomu kodu PHP. Przedstawione poniżej polecenie SQL powoduje utworzenie wyzwalacza. Należy je wykonać z poziomu narzędzia SQL*Plus po nawiązaniu połączenia 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 powyżej wyzwalacza logons_insert należy z kodu funkcji login(), która znajduje się w skrypcie userLoginTrans.php, usunąć poniższy 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 zakończyła 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 zwrócić uwagę, że powyższa modyfikacja funkcji login() nie wymaga zmiany istnieją- cego kodu, który implementuje tę funkcję. Dlatego też w celu sprawdzenia uaktualnionej wersji funkcji login() nadal można wykorzystać skrypt testLoginTrans.php, przedstawiony w poprzed- niej sekcji. Powinien on wygenerować takie same jak poprzednio dane wyjściowe. Wycofanie na poziomie polecenia Przeglądając kod uaktualnionej funkcji login(), Czytelnik może zauważyć, ż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 każdy błąd wykryty podczas działania polecenia INSERT spowoduje wycofanie wszystkich zmian wprowadzonych przez polecenie INSERT. Z kolei jeżeli wykonanie polecenia INSERT zakończy się powodzeniem, zmiany zostaną automatycznie zatwierdzone. Jak dotąd wszystko idzie dobrze. Co się jednak zdarzy, jeśli polecenie UPDATE, wywołane z po- ziomu wyzwalacza, zakończy swoje działanie niepowodzeniem? Czy spowoduje to wycofanie zmian wprowadzonych przez polecenie INSERT? Prostym testem pomagającym w odpowiedzi na te pytania jest tymczasowe zmodyfikowanie polecenia UPDATE w wyzwalaczu logons_trigger w taki sposób, aby działanie operacji UPDATE zawsze kończyło się niepowodzeniem. Następnie należy uruchomić skrypt testLoginTrans.php, który omówiono w podrozdziale „Nadzorowanie transakcji z poziomu PHP”, i zobaczyć co się zdarzy. W celu ponownego utworzenia wyzwalacza, aby wykonanie jego polecenia UPDATE zawsze kończyło się niepowodzeniem, można użyć przedstawionego poniżej 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 zwrócić uwagę na fakt, że chociaż wykonanie polecenia UPDATE w wyzwala- czu zawsze będzie kończyło się niepowodzeniem, sam wyzwalacz zostanie poprawnie skom- pilowany. Teraz, po uruchomieniu skryptu testLoginTrans.php, powinny zostać wyświetlone następujące dane wyjściowe: Uwierzytelnienie zakończyło się niepowodzeniem 120 Rozdział 4. • Transakcje Jak można się przekonać, proces uwierzytelniania zakończył się niepowodzeniem. Aby upew- nić się, że wykonanie polecenia INSERT w tabeli logons również będzie miało taki wynik, można obliczać liczbę rekordów tabeli przed i po wykonaniu skryptu testLoginTrans.php. Taki efekt da się osiągnąć za pomocą poniższego polecenia SQL, które wydano z poziomu narzędzia SQL*Plus po nawiązaniu połączenia z bazą danych jako usr/usr: SELECT count(*) FROM logons; Czytelnik powinien przekonać się, że po wykonaniu skryptu testLoginTrans.php liczba rekordów tabeli logons pozostanie taka sama. Stanowi to dowód, że niepowodzenie uaktualnienia tabeli logons za pomocą wyzwalacza logons_insert BEFORE INSERT, obejmującego tabelę accounts, po- woduje także wycofanie zmian wprowadzonych przez polecenie INSERT. Ogólnie rzecz biorąc, jeżeli w trakcie wykonywania wyzwalacza nastąpi błąd, wycofane zostaną wszyst- kie operacje, które spowodowały uruchomienie go. Wynika to z działania tak zwanego wycofywana na poziomie rekordu — czyli każdy błąd powstały podczas wykonywania polecenia spowoduje wycofanie wszystkich zmian wprowadzonych przez to polecenie. Jednak powyższe stwierdzenie nie zawsze jest prawdziwe. Na przykład wyzwalacz logons_insert może zostać zaimplementowany w taki sposób, że efekty działania polecenia INSERT nie zo- staną wycofane, kiedy wykonanie polecenia UPDATE z tego wyzwalacza zakończy się niepowo- dzeniem. Warto przeanalizować przedstawioną poniżej 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ć wyświetlone dane wyj- ściowe o podobnej postaci: Witaj Bob Robinson Odwiedziłeś nas już 3 raz(y) Twoja nazwa konta: bob Następnie jeżeli skrypt zostanie uruchomiony ponownie, wyświetlana liczba operacji logowa- nia pozostanie taka sama. Jednak po sprawdzeniu liczby rekordów tabeli logons, jak przed- stawiono we wcześniejszej części podrozdziału, będzie można dostrzec, że kolejne wykonanie skryptu testLoginTrans.php spowodowało zwiększenie wartości tej liczby. 121 PHP i Oracle. Tworzenie aplikacji webowych: od przetwarzania danych po Ajaksa Wskazuje to, że chociaż wykonanie polecenia UPDATE z wyzwalacza zakończyło się niepowo- dzeniem, wykonanie polecenia INSERT zakończyło się powodzeniem. Wynika to z faktu, że omówiony powyżej wyzwalacz logons_insert powoduje ciche zignorowanie jakiegokolwiek błędu zgłaszanego podczas jego wykonywania. W sekcji WHEN OTHERS — która jest jedyną procedurą obsługi wyjątków w części wyzwalacza odpowiedzialnej za obsługę wyjątków — ustalono wartość NULL. W większości przypadków zastosowanie powyżej techniki nie jest zalecane, ponieważ powoduje zmianę oczekiwanego sposobu zachowania bazy danych. Rozsądne założenie jest takie, że jeśli podczas wyko- nywania jakiegokolwiek polecenia SQL wystąpi błąd, modyfikacje wprowadzone przez to polecenie są automatycznie wycofywane. Dlatego też zamiast ustawiać wartość NULL w procedurze obsługi wyjątków, należy utworzyć kod, który będzie podejmował odpowiednie działania w odpowiedzi na wystąpienie błędu. Na przykład można wykorzystać procedurę RAISE_APPLICATION_ERROR w celu wygenerowania zdefiniowanego przez użytkownika błędu ORA. Znajdujący się poniżej fragment kodu poka- zuje, w jaki sposób wyzwalacz logons_insert mógłby zostać zmodyfikowany, aby wywoływać RAISE_APPLICATION_ERROR z poziomu procedury obsługi błędów: 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 powiodło się. ); END; / W powyższym wyzwalaczu procedura obsługi wyjątków wyraźnie wywołuję procedurę RAISE_ (cid:180)APPLICATION_ERROR w celu wygenerowania błędu ORA zdefiniowanego przez użytkownika. Jeżeli w pliku konfiguracyjnym php.ini parametr display_errors ma wartość On, omówiony w pod- rozdziale „Nadzorowanie transakcji z poziomu PHP” skrypt userLoginTrans.php spowoduje wyświetlenie komunikatu błędu wskazanego jako drugi parametr procedury RAISE_APPLICATION_ERROR. Teraz, po uruchomieniu skryptu testLoginTrans.php, powinien zostać wyświetlony następują- cy komunikat: Uwierzytelnienie zakończyło się niepowodzeniem 122 Rozdział 4. • Transakcje Liczba rekordów 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 również przez polecenie INSERT. Przed zakończeniem pracy z tym przykładem należy się upewnić o ponownym utworzeniu wyzwalacza logons_trigger, aby klauzula SET w jego poleceniu UPDATE przedstawiała się na- stępująco: SET num_logons = num_logons + 1 Rozważania dotyczące izolacji transakcji Kiedy transakcja modyfikuje rekord tabeli bazy danych, Oracle nakłada na niego blokadę utrzymywaną aż do chwili zatwierdzenia bądź wycofania tej transakcji. Celem takiego zacho- wania jest niedopuszczenie do sytuacji, w której dwie współbieżne transakcje będą modyfi- kowały ten sam rekord. Bardzo ważne jest, aby w tym miejscu wspomnieć, że rekordy z nałożonymi blokadami nadal mogą być odczytywane zarówno przez transakcje uaktualniające rekordy, jak i inne transak- cje. Różnica między dwiema wymienionymi transakcjami polega na tym, że transakcja nakła- dająca blokadę może zauważyć zmiany natychmiast po wykonaniu polecenia modyfikującego te rekordy. Natomiast inna transakcja nie może zobaczyć tych zmian aż do chwili zatwierdze- nia zmian przez transakcję, która nałożyła blokadę. Podczas gdy zastosowany w bazie danych Oracle mechanizm nakładania blokad został szcze- gółowo omówiony w dokumentacji Oracle (w rozdziale „Data Concurrency and Consistency” w podręczniku użytkownika Oracle Database Concepts), w podrozdziale przedstawiono ogól- ny opis działania izolacji transakcji w apl
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

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

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: