Zend_Db
i powiązane z nim klasy udostępniają prosty interfejs
dla baz danych SQL z poziomu Zend Framework. Klasa
Zend_Db_Adapter
jest podstawowym komponentem potrzebnym by
połączyć aplikację PHP z systemem zarządzania bazą danych (RDBMS).
Dla każdego rodzaju bazy danych istnieje oddzielna klasa adaptera
Zend_Db
.
Adaptery Zend_Db
tworzą połączenie pomiędzy rozszerzeniami
PHP dla konkretnych rodzajów baz danych a wspólnym interfejsem,
dzięki czemu można napisać aplikację raz i w nieskomplikowany sposób uruchamiać
ją z wieloma rodzajami RDBMS
Interfejs klasy adaptera jest podobny do interfejsu rozszerzenia
PHP Data Objects. Zend_Db
zawiera klasy adapterów dla sterowników PDO następujących rodzajów
baz danych:
-
IBM DB2 oraz Informix Dynamic Server (IDS), poprzez rozszerzenie PHP pdo_ibm.
-
MySQL, poprzez rozszerzenie PHP pdo_mysql
-
Microsoft SQL Server, używając rozszerzenia PHP pdo_dblib
-
Oracle, poprzez rozszerzenie PHP pdo_oci
-
PostgreSQL, poprzez rozszerzenie PHP pdo_pgsql
-
SQLite, używając rozszerzenia PHP pdo_sqlite
Dodatkowo Zend_Db
dostarcza klas adapterów korzystających
z rozszerzeń PHP dla następujących rodzajów
baz danych:
-
MySQL, poprzez rozszerzenie PHP mysqli
-
Oracle, poprzez rozszerzenie PHP oci8
-
IBM DB2 oraz DB2/i5, poprzez rozszerzenie PHP ibm_db2
-
Firebird/Interbase, poprzez rozszerzenie PHP php_interbase
Uwaga
Każdy adapter Zend_Db
używa określonego rozszerzenia
PHP. Aby użyć adaptera należy mieć zainstalowane i włączone
odpowiadające mu rozszerzenie PHP. Np. aby użyć dowolnego
adaptera PDO Zend_Db
, wymagane jest
posiadanie włączonego rozszerzenia PDO oraz sterownika dla
danego rodzaju RDBMS.
Ta część opisuje jak tworzy się instancję adaptera bazy danych. Jest to odpowiednik połączenia z bazą danych w aplikacji PHP.
Można utworzyć instancję adaptera za pomocą konstruktora. Przyjmuje on pojedynczy argument - tablicę parametrów używanych do deklaracji połączenia.
Przykład 186. Użycie konstruktora adaptera
$db = new Zend_Db_Adapter_Pdo_Mysql(array( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test' ));
Alternatywą w stosunku do bezpośredniego używania konstruktora jest utworzenie
instancji adaptera za pomocą statycznej metody
Zend_Db::factory()
. Ta metoda dynamicznie ładuje plik
klasy adaptera używając
Zend_Loader::loadClass().
Pierwszy argument metody to łańcuch znaków, który wyznacza nazwę bazową klasy
adaptera. Np. string 'Pdo_Mysql
' odpowiada klasie
Zend_Db_Adapter_Pdo_Mysql
. Drugi argument to ta sama
tablica parametrów, którą należało podać adapterowi konstruktora.
Przykład 187. Użycie metody fabryki adaptera
// Poniższa instrukcja jest zbędna ponieważ plik z klasą // Zend_Db_Adapter_Pdo_Mysql zostanie załadowany przez fabrykę // Zend_Db // require_once 'Zend/Db/Adapter/Pdo/Mysql.php'; // Załaduj klasę Zend_Db_Adapter_Pdo_Mysql automatycznie // i utwórz jej instancję $db = Zend_Db::factory('Pdo_Mysql', array( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test' ));
Jeśli jest zdefiniowana własna klasa dziedzicząca po
Zend_Db_Adapter_Abstract
ale jej nazwa nie zawiera
"Zend_Db_Adapter
", można użyć metody
factory()
do załadowania adaptera jedynie jeśli
poda się swój prefiks nazwy adaptera z kluczem 'adapterNamespace' do
argumentu zawierającego parametry połączenia.
Przykład 188. Użycie metody fabryki dla własnej klasy adaptera
// Nie trzeba ładować pliku klasy adaptera // bo robi to metoda fabryki Zend_Db // Załadowanie klasy MyProject_Db_Adapter_Pdo_Mysql automatycznie // i utworzenie jej instancji $db = Zend_Db::factory('Pdo_Mysql', array( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test', 'adapterNamespace' => 'MyProject_Db_Adapter' ));
Każdy z argumentów metody factory()
może również zostać
podany w formie obiektu klasy Zend_Config.
Jeśli pierwszy argument jest obiektem Zend_Config
to wymagane jest aby posiadał właściwość o nazwie
adapter, w której będzie zapisany łańcuch znaków
określający nazwę bazową klasy adaptera. Opcjonalnie, obiekt ten może zawierać
właściwość 'params' z właściwościami potomnymi
odpowiadającymi nazwom parametrów adaptera. Będą one użyte jedynie w
przypadku braku drugiego argumentu metody
factory()
.
Przykład 189. Użycie metody fabryki adaptera z obiektem Zend_Config
W poniższym przykładzie, obiekt Zend_Config
jest utworzony z tablicy.
Można również załadować dane z pliku zewnętrznego poprzez klasy
Zend_Config_Ini oraz
Zend_Config_Xml.
$config = new Zend_Config( array( 'database' => array( 'adapter' => 'Mysqli', 'params' => array( 'host' => '127.0.0.1', 'dbname' => 'test', 'username' => 'webuser', 'password' => 'secret', ) ) ) ); $db = Zend_Db::factory($config->database);
Drugi argument metody factory()
może stanowić tablicę
asocjacyjną zawierającą wartości odpowiadające parametrom adaptera. Ten argument
jest opcjonalny. Jeśli pierwszy argument jest obiektem klasy
Zend_Config
to powinien zawierać wszystkie parametry a
drugi argument jest ignorowany.
Poniższa lista opisuje parametry wspólne dla klas adapterów
Zend_Db
.
-
host: łańcuch znaków zawierający nazwę hosta lub adres IP serwera bazy danych. Jeśli baza danych jest uruchomiona na tej samej maszynie co aplikacja to można tu umieścić 'localhost' lub '127.0.0.1'.
-
username: identyfikator użytkownika używany do autoryzacji połączenia z serwerem bazy danych.
-
password: hasło użytkownika używane do autoryzacji połączenia z serwerem bazy danych.
-
dbname: nazwa instancji bazy danych na serwerze.
-
port: niektóre serwery bazy danych używają do komunikacji numeru portu określonego przez administratora. Ten parametr pozwala na ustawienie numeru portu przez który aplikacja PHP się łączy tak aby zgadzał się z tym ustawionym na serwerze bazy danych.
-
charset: określenie zestawu znaków używanego podczas połączenia.
-
options: ten parametr to tablica asocjacyjna opcji obsługiwanych przez wszystkie klasy
Zend_Db_Adapter
. -
driver_options: ten parametr to tablica asocjacyjna zawierająca dodatkowe opcje specyficzne dla każdego rozszerzenia bazy danych. Typowym przykładem użycia tego parametru jest zbiór atrybutów sterownika PDO.
-
adapterNamespace: początkowa część nazwy klasy używanego adaptera, używana zamiast '
Zend_Db_Adapter
'. Przydatna w przypadku użycia metodyfactory()
do załadowana własnej klasy adaptera.
Przykład 190. Przekazanie do fabryki opcji zmiany wielkości znaków
Opcję tą można podać za pomocą stałej
Zend_Db::CASE_FOLDING
.
Odpowiada ona atrybutowi ATTR_CASE
w PDO
oraz rozszerzeniu IBM DB2, który zmienia wielkość znaków w nazwach kolumn
zwracanych w rezultacie zapytania. Opcja przybiera wartości
Zend_Db::CASE_NATURAL
(bez zmiany - domyślnie),
Zend_Db::CASE_UPPER
(zmiana na wielkie znaki) oraz
Zend_Db::CASE_LOWER
(zmiana na małe znaki).
$options = array( Zend_Db::CASE_FOLDING => Zend_Db::CASE_UPPER ); $params = array( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test', 'options' => $options ); $db = Zend_Db::factory('Db2', $params);
Przykład 191. Przekazanie do fabryki opcji automatycznego umieszczania w cudzysłowie
Tą opcję można podać za pomocą stałej
Zend_Db::AUTO_QUOTE_IDENTIFIERS
.
Jeśli jej wartość wynosi TRUE
(domyślnie) to identyfikatory
takie jak nazwy tabel, kolumn oraz aliasy w składni każdego polecenia
SQL generowanego za pomocą danego adaptera będą
umieszczane w cudzysłowie. Takie podejście upraszcza używanie identyfikatorów
zawierających słowa kluczowe SQL lub znaki specjalne. Jeśli
wartość opcji wynosi FALSE
to identyfikatory nie są
umieszczane w cudzysłowie. Jeśli zachodzi potrzeba owinięcia identyfikatorów
cudzysłowami należy to zrobić samodzielnie za pomocą metody
quoteIdentifier()
.
$options = array( Zend_Db::AUTO_QUOTE_IDENTIFIERS => false ); $params = array( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test', 'options' => $options ); $db = Zend_Db::factory('Pdo_Mysql', $params);
Przykład 192. Przekazanie do fabryki opcji sterownika PDO
$pdoParams = array( PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true ); $params = array( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test', 'driver_options' => $pdoParams ); $db = Zend_Db::factory('Pdo_Mysql', $params); echo $db->getConnection() ->getAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY);
Przykład 193. Przekazanie do fabryki opcji serializacji
$options = array( Zend_Db::ALLOW_SERIALIZATION => false ); $params = array( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test', 'options' => $options ); $db = Zend_Db::factory('Pdo_Mysql', $params);
Utworzenie instancji klasy adaptera nie powoduje natychmiastowego połączenia z serwerem bazy danych. Adapter zachowuje parametry połączenia ale łączy się na żądanie - w momencie pierwszego wywołania zapytania. Dzięki temu zainicjowanie adaptera jest szybkie i tanie. Można utworzyć adapter nawet jeśli nie jest się pewnym czy wykonanie jakiegokolwiek zapytania przy danym połączeniu będzie niezbędne.
Jeśli zajdzie potrzeba zmuszenia adaptera do połączenia z bazą danych,
należy wówczas wywołać metodę getConnection()
.
Zwraca ona obiekt połączenia odpowiednio do rozszerzenia
PHP używanego do połączenia. Jeśli
używa się adaptera korzystającego z PDO, to metoda
getConnection()
, po zainicjowaniu połączenia
z serwerem bazy danych, zwróci obiekt PDO.
Możliwość wymuszenia połączenia z bazą danych może być przydatna gdy chce się złapać wyjątki rzucane przez adapter powstałe w rezultacie podania złych danych uwierzytelniających lub innych błędów połączenia. Te wyjątki nie są rzucane dopóki nie jest ustanowiona próba połączenia, więc można uprościć kod aplikacji i obsłużyć je w jednym miejscu. W przeciwnym razie należałoby je przechwycać w momencie wywołania pierwszego zapytania do bazy danych.
Dodatkowo adapter może zostać poddany serializacji i przechowany
np. w zmiennej sesyjnej.
Może to być pomocne nie tylko dla adaptera ale również z punktu widzenia obiektów,
które z niego korzystają, takich jak Zend_Db_Select
.
Domyślnie serializacja adapterów jest dozwolona ale jeśli jest taka
potrzeba - można ją wyłączyć poprzez podanie opcji
Zend_Db::ALLOW_SERIALIZATION
z wartością
FALSE
(przykład niżej).
Aby pozostać w zgodzie z zasadą leniwego połączenia, adapter nie połączy się
automatycznie po odserializowaniu. Należy zatem
wywołać metodę getConnection()
.
Można również zmusić adapter aby po odserializowaniu łączył się z bazą
danych automatycznie poprzez podanie opcji
Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE
z wartością TRUE
.
Przykład 194. Obsługa wyjątków połączenia
try { $db = Zend_Db::factory('Pdo_Mysql', $parameters); $db->getConnection(); } catch (Zend_Db_Adapter_Exception $e) { // przyczyną problemów mogą być złe dane uwierzytelniające lub np. baza danych // nie jest uruchomiona } catch (Zend_Exception $e) { // przyczyną może być np. problem z załadowaniem odpowiedniej klasy adaptera }
W dokumentacji klas Zend_Db
używany jest prosty zestaw tabel w
celu zilustrowania użycia klas i metod. Te tabele mogą przechowywać dane związane z
przechowywaniem błędów (bugs) powstałych podczas rozwijania projektu informatycznego.
Baza danych zawiera cztery tabele:
-
accounts przechowuje informacje o każdym użytkowniku bazy danych błędów.
-
products przechowuje informacje o każdym produkcie, dla którego można zapisać wystąpienie usterki.
-
bugs przechowuje informacje o błędach, włączając jego obecny stan, osobę zgłaszającą, osobę przypisaną do rozwiązania problemu oraz osobę przeznaczoną do zweryfikowania poprawności zastosowanego rozwiązania.
-
bugs_products przechowuje relację pomiędzy usterkami a produktami. To odzwierciedla połączenie wiele-do-wielu, ponieważ dany błąd może się odnosić do wielu produktów a jeden produkt może posiadać wiele usterek.
Poniższy pseudokod definicji danych SQL opisuje tabele z tego
przykładu. Te tabele są bardzo często używane w testach jednostkowych
Zend_Db
.
CREATE TABLE accounts ( account_name VARCHAR(100) NOT NULL PRIMARY KEY ); CREATE TABLE products ( product_id INTEGER NOT NULL PRIMARY KEY, product_name VARCHAR(100) ); CREATE TABLE bugs ( bug_id INTEGER NOT NULL PRIMARY KEY, bug_description VARCHAR(100), bug_status VARCHAR(20), reported_by VARCHAR(100) REFERENCES accounts(account_name), assigned_to VARCHAR(100) REFERENCES accounts(account_name), verified_by VARCHAR(100) REFERENCES accounts(account_name) ); CREATE TABLE bugs_products ( bug_id INTEGER NOT NULL REFERENCES bugs, product_id INTEGER NOT NULL REFERENCES products, PRIMARY KEY (bug_id, product_id) );
Należy zwrócić uwagę, iż tabela 'bugs' zawiera wiele kluczy obcych odnoszących się do tabeli 'accounts'. Każdy z nich może prowadzić do innego wiersza tabeli 'accounts' w ramach jednego bugu.
Poniższy diagram ilustruje fizyczny model danych przykładowej bazy danych
Ta część opisuje metody klasy adaptera za pomocą których można wywołać zapytania SELECT oraz pobrać ich rezultaty.
Za pomocą metody fetchAll()
można wywołać zapytanie
SQL SELECT oraz pobrać jego rezultaty
w jednym kroku.
Pierwszym argumentem metody jest łańcuch znaków zawierający polecenie SELECT. Alternatywnie, w pierwszym argumencie można umieścić obiekt klasy Zend_Db_Select. Adapter automatycznie dokonuje konwersji tego obiektu do łańcucha znaków zawierającego zapytanie SELECT.
Drugi argument metody fetchAll()
to tablica wartości
używanych do zastąpienia parametrów wiązanych w zapytaniu SQL.
Przykład 195. Użycie metody fetchAll()
$sql = 'SELECT * FROM bugs WHERE bug_id = ?'; $result = $db->fetchAll($sql, 2);
Domyślnie fetchAll()
zwraca tablicę wierszy, z których
każdy jest tablicą asocjacyjną. Kluczami tablicy asocjacyjnej są kolumny lub ich
aliasy podane w zapytaniu SELECT.
Można ustawić inny tryb zwracania rezultatów poprzez metodę
setFetchMode()
. Dopuszczalne tryby są identyfikowane
przez stałe:
-
Zend_Db::FETCH_ASSOC: zwraca dane w postaci tablicy tablic asocjacyjnych. Klucze tablicy asocjacyjnej to nazwy kolumn. To jest domyślny tryb zwrotu danych w klasach
Zend_Db_Adapter
.Należy zwrócić uwagę na fakt iż jeśli lista kolumn do zwrotu zawiera więcej niż jedną kolumnę o określonej nazwie, np. jeśli pochodzą one z różnych tabel połączonych klauzulą JOIN, to w asocjacyjnej tablicy wynikowej może być tylko jeden klucz o podanej nazwie. Jeśli używany jest tryb FETCH_ASSOC, należy upewnić się, że kolumny w zapytaniu SELECT posiadają aliasy, dzięki czemu rezultat zapytania będzie zawierał unikatowe nazwy kolumn.
Domyślnie, łańcuchy znaków z nazwami kolumn są zwracane w taki sposób w jaki zostały otrzymane przez sterownik bazy danych. Przeważnie jest odpowiada to stylowi nazw kolumn używanego rodzaju bazy danych. Dzięki opcji
Zend_Db::CASE_FOLDING
można określić wielkość zwracanych znaków. Opcji tej można użyć podczas inicjowania adaptera. Przykład: Przykład 190, „Przekazanie do fabryki opcji zmiany wielkości znaków”. -
Zend_Db::FETCH_NUM: zwraca dane jako tablicę tablic. Indeksami tablicy są liczby całkowite odpowiadające pozycji danej kolumny w liście SELECT zapytania.
-
Zend_Db::FETCH_BOTH: zwraca dane jako tablicę tablic. Kluczami tablicy są zarówno łańcuchy znaków (tak jak w trybie FETCH_ASSOC) oraz liczby całkowite (tak jak w trybie FETCH_NUM). Należy zwrócić uwagę na fakt iż liczba elementów tablicy wynikowej będzie dwukrotnie większa niż w przypadku użycia trybów FETCH_ASSOC lub FETCH_NUM.
-
Zend_Db::FETCH_COLUMN: zwraca dane jako tablicę wartości. Wartości odpowiadają rezultatom zapytania przypisanym jednej kolumnie zbioru wynikowego. Domyślnie, jest to pierwsza kolumna, indeksy rozpoczynają się od 0.
-
Zend_Db::FETCH_OBJ: zwraca dane jako tablicę obiektów. Domyślną klasą jest wbudowana w PHP klasa stdClass. Kolumny rezultatu zapytania stają się właściwościami powstałego obiektu.
Przykład 196. Użycie metody setFetchMode()
$db->setFetchMode(Zend_Db::FETCH_OBJ); $result = $db->fetchAll('SELECT * FROM bugs WHERE bug_id = ?', 2); // $result jest tablicą obiektów echo $result[0]->bug_description;
Metoda fetchAssoc()
zwraca dane w formie tablicy tablic
asocjacyjnych, niezależnie od wartości ustalonej jako tryb
zwracania rezultatów zapytania.
Przykład 197. Użycie fetchAssoc()
$db->setFetchMode(Zend_Db::FETCH_OBJ); $result = $db->fetchAssoc('SELECT * FROM bugs WHERE bug_id = ?', 2); // $result staje się tablicą tablic asocjacyjnych, mimo ustawionego // trybu zwracania rezultatów zapytania echo $result[0]['bug_description'];
Metoda fetchCol()
zwraca dane w postaci tablicy wartości
niezależnie od wartości ustalonej jako tryb zwrcania rezultatów zapytania. Ta
metoda zwraca pierwszą kolumnę ze zbioru powstałego na skutek wywołania zapytania.
Inne kolumny znajdujące się w tym zbiorze są ignorowane. Aby zwrócić inną niż
pierwsza kolumnę należy skorzystać z przykładu
„Pobranie pojedynczej kolumny ze zbioru wynikowego”.
Przykład 198. Użycie fetchCol()
$db->setFetchMode(Zend_Db::FETCH_OBJ); $result = $db->fetchCol( 'SELECT bug_description, bug_id FROM bugs WHERE bug_id = ?', 2); // zawiera bug_description; bug_id nie zostanie zwrócona echo $result[0];
Metoda fetchPairs()
zwraca dane w postaci tablicy
par klucz-wartość. Zwracana jest to tablica asocjacyjna z pojedynczą wartością
w każdym polu. Wartości z pierwszej kolumny zapytania SELECT
stają się kluczami tablicy wynikowej zaś wartości drugiej zostają umieszczone
jako wartości tablicy. Pozostałe kolumny zwracane przez zapytanie są ignorowane.
Należy konstruować zapytanie SELECT w taki sposób aby pierwsza kolumna posiadała unikalne wartości. W przeciwnym wypadku wartości tablicy asocjacyjnej zostaną nadpisane.
Przykład 199. Użycie fetchPairs()
$db->setFetchMode(Zend_Db::FETCH_OBJ); $result = $db->fetchPairs('SELECT bug_id, bug_status FROM bugs'); echo $result[2];
Metoda fetchRow()
pobiera dane używając bieżącego
trybu zwracania rezultatów ale zwraca jedynie pierwszy wiersz ze zbioru
wynikowego.
Przykład 200. Using fetchRow()
$db->setFetchMode(Zend_Db::FETCH_OBJ); $result = $db->fetchRow('SELECT * FROM bugs WHERE bug_id = 2'); // $result to pojedynczy obiekt a nie tablica obiektów echo $result->bug_description;
Metoda fetchOne()
można opisać jako kombinacja
fetchRow()
oraz fetchCol()
bo zwraca dane pochodzące z pierwszego wiersza zbioru wynikowego ograniczając
kolumny do pierwszej w wierszu. Ostatecznie zostaje zwrócona pojedyncza
wartość skalarna a nie tablica czy obiekt
Przykład 201. Using fetchOne()
$result = $db->fetchOne('SELECT bug_status FROM bugs WHERE bug_id = 2'); // pojedyncza wartość string echo $result;
Adaptera klasy można użyć również do zapisania nowych, bądź do zmiany istniejących danych w bazie. Ta część opisuje metody włąściwe dla tych operacji.
Za pomocą metody insert()
można dodać nowe wiersze
do tabeli bazy danych. Jej pierwszym argumentem jest łańcuch znaków oznaczający
nazwę tabeli. Drugim - tablica asocjacyjna z odwzorowaniem nazw kolumn i wartości
jakie mają zostać w nich zapisane.
Przykład 202. Dodawanie danych do tabeli
$data = array( 'created_on' => '2007-03-22', 'bug_description' => 'Something wrong', 'bug_status' => 'NEW' ); $db->insert('bugs', $data);
Kolumny, które nie zostały podane w tablicy z danymi nie będą umieszczone
w zapytaniu na zasadzie analogicznej do użycia polecenia
SQL INSERT:
Jeśli kolumna ma podaną wartość domyślną (DEFAULT)
to ta wartość zostanie zapisana w nowym wierszu.
W przeciwnym przypadku kolumna nie będzie miała żadnej
wartości (NULL
).
Domyślnym sposobem zapisu danych jest użycie parametrów wiązanych. Dzięki temu ryzyko wystąpienia niektórych form zagrożenia bezpieczeństwa aplikacji jest ograniczone. W tablicy z danymi nie trzeba używać unikania lub umieszczania wartości w cudzysłowiu.
Może wystąpić potrzeba potraktowania wartości w tablicy danych jako wyrażeń
SQL. W takim wypadku nie powinno się stosować
umieszczania w cudzysłowiu.
Domyślnie wszystkie podane wartości string są traktowane jak literały.
Aby upewnić się, że
wartość jest wyrażeniem SQL i nie powinna zostać umieszczona w
cudzysłowie, należy ją podać jako obiekt klasy
Zend_Db_Expr
zamiast
prostego łańcucha znaków.
Przykład 203. Umieszczanie wyrażeń w tabeli
$data = array( 'created_on' => new Zend_Db_Expr('CURDATE()'), 'bug_description' => 'Something wrong', 'bug_status' => 'NEW' ); $db->insert('bugs', $data);
Niektóre systemy zarządzania bazą danych wspierają klucze pierwotne o automatycznie
zwiększanych wartościach. Tabela zdefiniowana w ten sposób generuje wartość klucza
pierwotnego automatycznie przy każdym poleceniu INSERT.
Wartością zwracaną przez metodę
insert()
nie jest
ostatni zapisany identyfikator, ponieważ tabela mogła nie posiadać automatycznie
inkrementowanej kolumny.
Zamiast tego wartością zwrotną jest ilość zapisanych wierszy (przeważnie 1).
Jeśli tabela jest zdefiniowana za pomocą automatycznego klucza pierwotnego to można
użyć metody lastInsertId()
.
Po udanym dodaniu wiersza metoda
ta zwraca ostatnią wartość klucza wygenerowaną w ramach bieżącego połączenia.
Przykład 204. Użycie lastInsertId() dla automatycznego klucza pierwotnego
$db->insert('bugs', $data); // zwrócenie ostatniej wartości wygenerowanej przez automatyczną kolumnę $id = $db->lastInsertId();
Niektóre systemy zarządzania bazą danych wspierają obiekt sekwencji, który służy
do generowania unikalnych wartości, które mogą posłużyć jako klucz pierwotny.
Aby obsługiwać również sekwencje metoda lastInsertId()
akceptuje dodatkowe dwa argumenty. Pierwszym z nich jest nazwa tabeli zaś
drugim - nazwa kolumny. Założona jest konwencja według której sekwencja ma nazwę
składającą się z nazwy tabeli oraz kolumny do której generuje wartości z dodatkowym
sufiksem "_seq". Podstawą tego założenia są domyślne ustawienia PostgreSQL.
Przykładowo tabela "bugs" z kluczem pierwotnym w kolumnie "bug_id"
będzie używała sekwencji o nazwie "bugs_bug_id_seq".
Przykład 205. Użycie lastInsertId() dla sekwencji
$db->insert('bugs', $data); // zwrócenie ostatniej wartości wygenerowanej przez sekwencję 'bugs_bug_id_seq' $id = $db->lastInsertId('bugs', 'bug_id'); // zwrócenie ostatniej wartości wygenerowanej przez sekwencję 'bugs_seq' $id = $db->lastInsertId('bugs');
Jeśli nazwa obiektu sekwencji nie podąża za tą konwencją można użyć metody
lastSequenceId()
, która przyjmuje pojedynczy łańcuch
znaków - nazwę sekwencji - jako argument.
Przykład 206. Użycie lastSequenceId()
$db->insert('bugs', $data); // zwrócenie ostatniej wartości wygenerowanej przez sekwencję 'bugs_id_gen' $id = $db->lastSequenceId('bugs_id_gen');
Dla systemów zarządzania bazą danych które nie wspierają sekwencji, włączając MySQL,
Microsoft SQL Server, oraz SQLite dodatkowe argumenty podane do
metody lastInsertId()
są ignorowane a zwrócona jest
ostatnia wartość wygenerowana dla dowolnej tabeli poprzez polecenie
INSERT
podczas bieżącego połączenia. Dla tych RDBMS metoda
lastSequenceId()
zawsze zwraca NULL
.
Dlaczego nie należy używać "SELECT MAX(id) FROM table"?
Powyższe zapytanie często zwraca ostatni klucz pierwotny, jaki został zapisany
w wierszu tabeli. Ten sposób nie jest jednak bezpieczny w przypadku, gdy
wiele klientów zapisuje rekordy do bazy danych. Jest możliwe, że w momencie
pomiędzy zapisaniem jednego rekordu a zapytaniem o
MAX(id)
, do tabeli zostanie zapisany kolejny rekord,
wprowadzony przez innego użytkownika. Przez to zwrócona wartość nie będzie
identyfikowała pierwszego wprowadzonego wiersza tylko drugi - wprowadzony przez
inne połączenie. Nie ma pewnego sposobu na wykrycie, że do takiego zdarzenia
doszło.
Zastosowanie mocnej izolacji transakcji, tak jak przy trybie "repeatable read" może pomóc w ograniczeniu ryzyka wystąpienia takiej sytuacji ale niektóre systemy zarządzania bazą danych nie wspierają izolacji transakcji w wystarczającym stopniu lub aplikacja może intencjonalnie korzystać jedynie z niskiego trybu izolacji transakcji.
Dodatkowo, używanie wyrażeń takich jak "MAX(id)+1" do generowania nowych wartości klucza głównego nie jest bezpieczne bo dwa połączenia mogą wykonać to zapytanie praktycznie jednocześnie i w rezultacie próbować użyć jednakowej wartości dla kolejnego polecenia INSERT.
Wszystkie systemy zarządzania bazą danych udostępniają mechanizmy służące generowaniu unikalnych wartości oraz zwracaniu ostatniej z nich. Mechanizmy te intencjonalnie działają poza zasięgiem izolacji transakcji więc nie jest możliwe aby wartość wygenerowana dla jednego klienta pojawiła się jako ostatnia wygenerowana dla innego połączenia.
Aktualizacji wierszy tabeli w bazie danych można dokonać poprzez metodę adaptera
update()
. Metoda przyjmuje trzy argumenty: pierwszym
jest nazwa tabeli; drugim - tablica asocjacyjna mapująca kolumny, które mają ulec
zmianie oraz wartości jakie kolumny przybiorą; trzecim - warunek
wyznaczający wiersze do zmiany.
Wartości w tablicy z danymi są traktowane jak literały znakowe. Należy zapoznać się z akapitem „Dodawanie danych” aby uzyskać więcej informacji na temat użyci w niej wyrażeń SQL.
Trzecim argumentem metody jest string zawierający wyrażenie SQL będące kryterium wyznaczającym wiersze do zmiany. Wartości i identyfikatory w tym argumencie nie są umieszczane w cudzysłowie ani unikane. Należy, więc, zadbać o to samemu. Należy zapoznać się z akapitem „Umieszczanie wartości i identyfikatorów w cudzysłowie” aby zasięgnąć dodatkowych informacji.
Wartością zwracaną jest ilość wierszy zmienionych przez operację aktualizacji.
Przykład 207. Aktualizacja wierszy
$data = array( 'updated_on' => '2007-03-23', 'bug_status' => 'FIXED' ); $n = $db->update('bugs', $data, 'bug_id = 2');
Jeśli trzeci argument nie zostanie podany to wszystkie wiersze w tabeli zostaną zaktualizowane zgodnie z kolumnami i wartościami podanymi w drugim argumencie.
Jeśli trzeci argument zostanie podany jako tablica łańcuchów znakowych to
w zapytaniu łańcuchy zostaną połączone za pomocą operatorów
AND
.
Przy podaniu trzeciego argumentu jako tablicy tablic, ich wartości
zostaną automatycznie
otoczone cudzysłowami i umieszczone w kluczach tych tablic. Po czym zostaną
połączone za pomocą operatorów AND
.
Przykład 208. Aktualizacja wierszy tablicy za pomocą tablicy wyrażeń
$data = array( 'updated_on' => '2007-03-23', 'bug_status' => 'FIXED' ); $where[] = "reported_by = 'goofy'"; $where[] = "bug_status = 'OPEN'"; $n = $db->update('bugs', $data, $where); // Powstałe wyrażenie SQL to: // UPDATE "bugs" SET "update_on" = '2007-03-23', "bug_status" = 'FIXED' // WHERE ("reported_by" = 'goofy') AND ("bug_status" = 'OPEN')
Przykład 209. Aktualizacja wierszy tablicy za pomocą tablicy tablic
$data = array( 'updated_on' => '2007-03-23', 'bug_status' => 'FIXED' ); $where['reported_by = ?'] = 'goofy'; $where['bug_status = ?'] = 'OPEN'; $n = $db->update('bugs', $data, $where); // Powstałe wyrażenie SQL to: // UPDATE "bugs" SET "update_on" = '2007-03-23', "bug_status" = 'FIXED' // WHERE ("reported_by" = 'goofy') AND ("bug_status" = 'OPEN')
Usuwania danych można dokonać używając metody delete()
.
Przyjmuje ona dwa argumenty: pierwszym z nich jest łańcuch znaków z nazwą tabeli;
Drugim - warunek określający wiersze do usunięcia.
Drugi argument to string zawierający wyrażenie SQL użyte jako kryterium wyznaczania usuwanych wierszy. Wartości i identyfikatory nie są unikane ani umieszczane w cudzysłowie - należy zatroszczyć się o to samemu. Aby dowiedzieć się więcej na ten temat można skorzystać z akapitu „Umieszczanie wartości i identyfikatorów w cudzysłowie”.
Wartość zwrotna to ilość wierszy, jakie uległy zmianie w wyniku zadziałania operacji usuwania.
Jeśli drugi argument nie zostanie podany to wszystkie wiersze z tabeli ulegną usunięciu.
Jeśli drugi argument zostanie podany jako tablica łańcuchów znaków to
te łańcuchy ulegną konkatenacji jako wyrażenia logiczne połączone
operatorem AND
.
Jeśli trzeci argument będzie tablicą tablic to jej wartości zostaną
automatycznie otoczone cudzysłowami i umieszczona w kluczach tablic. Potem
zostaną połączone razem za pomocą operatora AND
.
Podczas tworzenia zapytań SQL często dochodzi do sytuacji, w której niezbędne jest umieszczenie wartości zmiennych PHP w wyrażeniach SQL. Stanowi to zagrożenie, ponieważ jeśli wartość łańcuchowej zmiennej PHP zawiera określone znaki, takie jak symbol cudzysłowu, to mogą one spowodować błąd w poleceniu SQL. Poniżej znajduje się przykład zapytania zawierającego niespójną liczbę symboli cudzysłowu:
$name = "O'Reilly"; $sql = "SELECT * FROM bugs WHERE reported_by = '$name'"; echo $sql; // SELECT * FROM bugs WHERE reported_by = 'O'Reilly'
Zagrożenie potęguje fakt iż podobne błędy mogą zostać wykorzystane przez osobę próbującą zmanipulować działanie funkcji aplikacji. Jeśli takiej osobie uda się wpłynąć na wartość zmiennej PHP poprzez parametr HTTP (bądź inny mechanizm), to będzie mogła zmienić zapytanie SQL tak by dokonywało operacji zupełnie niezamierzonych przez twórców, takich jak zwrócenie danych, do których osoba nie powinna mieć dostępu. To jest poważny i szeroko rozpowszechniony sposób łamania zabezpieczeń aplikacji znany pod nazwą "SQL Injection" (wstrzyknięcie SQL - http://en.wikipedia.org/wiki/SQL_Injection).
Adaptery klasy Zend_Db
udostępniają funkcje przydatne
do zredukowania zagrożenia atakiem SQL Injection w kodzie
PHP.
Przyjętym rozwiązaniem jest unikanie znaków specjalnych takich jak cudzysłów w
wartościach zmiennych PHP
przed umieszczeniem ich w poleceniu SQL.
Takie podejście zapewnia ochronę przed przypadkową jak i intencjonalną zmianą
znaczenia poleceń SQL przez
zmienne PHP zawierające znaki specjalne.
Metoda quote()
przyjmuje pojedynczy
argument - łańcuch znaków.
Na wyjściu zwraca podany argument ze wszystkimi znakami specjalnymi
poddanymi uniknięciu w sposób właściwy dla używanego
RDBMS i otoczony znakami ograniczającymi
łańcuchy znakowe. Standardowym znakiem ograniczającym
stringi w SQL jest pojedynczy cudzysłów (').
Przykład 211. Użycie quote()
$name = $db->quote("O'Reilly"); echo $name; // 'O\'Reilly' $sql = "SELECT * FROM bugs WHERE reported_by = $name"; echo $sql; // SELECT * FROM bugs WHERE reported_by = 'O\'Reilly'
Należy zwrócić uwagę, że wartość zwrotna metody quote()
zawiera znaki ograniczające stringi. Jest to zachowanie różne od niektórych funkcji
które unikają specjalne znaki ale nie ujmują całego łańcucha w znaki ograniczające,
tak jak
mysql_real_escape_string().
Wartości mogą wymagać umieszczenia w cudzysłowach lub nie, zgodnie z
kontekstem używanego typu danych SQL.
W przypadku niektórych rodzajów systemów zarządzania
bazą danych liczby całkowite nie mogą być ograniczane cudzysłowami
jeśli są porównywane z kolumną lub wyrażeniem zwracającym inną liczbę całkowitą.
Innymi słowy, poniższy zapis może wywołać błąd w niektórych
implementacjach SQL zakładając, że
intColumn jest określona
typem danych INTEGER
.
SELECT * FROM atable WHERE intColumn = '123'
Można użyć opcjonalnego, drugiego argumentu metody quote()
aby określić typ danych SQL i ograniczyć stosowanie cudzysłowu.
Przykład 212. Użycie quote() z podanym typem danych SQL
$value = '1234'; $sql = 'SELECT * FROM atable WHERE intColumn = ' . $db->quote($value, 'INTEGER');
Każda klasa Zend_Db_Adapter
ma zapisane nazwy numerycznych
typów danych SQL odpowiednio do swojego rodzaju
RDBMS.
Zamiast tego można w tym miejscu również korzystać ze stałych
Zend_Db::INT_TYPE
,
Zend_Db::BIGINT_TYPE
oraz
Zend_Db::FLOAT_TYPE
aby uniezależnić kod
od rodzaju bazy danych.
Zend_Db_Table
automatycznie określa
typy danych SQL
dla metody quote()
podczas generowania
zapytań SQL odnoszących się do klucza pierwotnego tabeli.
Najbardziej typowym przypadkiem użycia cudzysłowu do ograniczania zmiennych jest
umieszczenie zmiennej PHP w zapytaniu SQL.
Aby to osiągnąć można użyć metody quoteInto()
.
Przyjmuje ona dwa argumenty: pierwszym jest łańcuch znaków zawierający
symbol "?", który zostanie zastąpiony; drugim jest zmienna
PHP, która ma trafić na miejsce "?".
Zastępowany symbol jest używany przez wielu producentów baz danych do oznaczenia
pozycyjnych parametrów wiązanych ale metoda quoteInto()
jedynie emuluje takie parametry. W wyniku jej działania wartość zmiennej jest
zwyczajnie umieszczana w łańcuchu z zapytaniem, po wstępnym uniknięciu specjalnych
znaków i umieszczeniu w cudzysłowie. Prawdziwa implementacja parametrów wiązanych
zakłada separację łańcucha znaków polecenia SQL od samych
parametrów oraz wstępne parsowanie polecenia na serwerze bazy danych.
Przykład 213. Użycie quoteInto()
$sql = $db->quoteInto("SELECT * FROM bugs WHERE reported_by = ?", "O'Reilly"); echo $sql; // SELECT * FROM bugs WHERE reported_by = 'O\'Reilly'
Można użyć opcjonalnego, trzeciego parametru metody
quoteInto()
aby określić typ danych SQL.
Numeryczne typy danych (w przeciwieństwie
do innych typów) nie podlegają umieszczaniu w cudzysłowie.
Przykład 214. Użycie quoteInto() z podaniem typu danych SQL
$sql = $db ->quoteInto("SELECT * FROM bugs WHERE bug_id = ?", '1234', 'INTEGER'); echo $sql; // SELECT * FROM bugs WHERE reported_by = 1234
Wartości nie są jedyną częścią składni polecenia SQL, która może być zmienna. W przypadku użycia zmiennych PHP do określenia tabel, kolumn lub innych identyfikatorów zapytania SQL, może zajść potrzeba umieszczenia również tych elementów w cudzysłowie. Domyślnie identyfikatory SQL muszą przestrzegać określonych reguł - podobnie jak w PHP oraz większości innych języków programowania. Przykładem takiej reguły jest zakaz używania spacji lub określonych znaków interpunkcyjnych, specjalnych ani też znaków spoza ASCII. Poza tym istnieje lista określonych słów, które służą do tworzenia zapytań - ich też nie powinno się używać jako identyfikatorów.
Mimo to SQL posiada ograniczone identyfikatory (delimited identifiers), dzięki którym można skorzystać z większego wachlarza znaków do nazywania obiektów. Jeśli określony identyfikator zostanie ograniczony odpowiednim rodzajem cudzysłowu to będzie można użyć znaków, które bez tego ograniczenia spowodowałyby błąd. Identyfikatory ograniczone mogą zawierać spacje, znaki interpunkcyjne czy lokalne litery. Można nawet używać zarezerwowanych słów SQL jeśli zostaną otoczone odpowiednimi znakami ograniczającymi.
Metoda quoteIdentifier()
zachowuje się podobnie jak
quote()
ale otacza podany łańcuch znaków za pomocą
znaków ograniczających zgodnie z rodzajem używanego adaptera.
Standardowy SQL
używa podwójnego cudzysłowu (") jako znaku ograniczającego a większość systemów
zarządzania bazą danych podąża za tym przykładem. MySQL domyślnie używa znaków
back-tick (`). Metoda quoteIdentifier()
dokonuje również
unikania znaków specjalnych znajdujących się w przekazanym argumencie.
Przykład 215. Użycie quoteIdentifier()
// można użyć tabeli o nazwie takiej samej jak słowo zarezerwowane SQL $tableName = $db->quoteIdentifier("order"); $sql = "SELECT * FROM $tableName"; echo $sql // SELECT * FROM "order"
W SQL identyfikatory ograniczone są wrażliwe na wielkość liter, w przeciwieństwie do zwykłych identyfikatorów. Przez to, należy upewnić się, że pisownia identyfikatora w 100% odpowiada pisowni zapisanej w schemacie, włącznie z wielkością liter.
W większości przypadków gdzie polecenie SQL jest
generowane wewnątrz klas Zend_Db
,
domyślnym zachowaniem jest automatyczne ograniczanie
identyfikatorów. Można to zmienić poprzez opcję
Zend_Db::AUTO_QUOTE_IDENTIFIERS
wywoływaną
podczas inicjalizacji adaptera.
Więcej informacji:
Przykład 191, „Przekazanie do fabryki opcji automatycznego umieszczania
w cudzysłowie”.
W świecie baz danych transakcja to zbiór operacji, który może zostać zapisany
bądź cofnięty za pomocą jednej instrukcji, nawet jeśli zmiany wynikające z tych operacji
dotyczyły wielu tabel. Wszystkie zapytania do bazy danych są przeprowadzane w
kontekście transakcji. Jeśli nie są zarządzane jawnie to sterownik bazy danych używa ich
w sposób przezroczysty dla użytkownika. Takie podejście nazywa się trybem
auto-commit - sterownik bazy danych tworzy transakcje dla każdego
tworzonego polecenia i zapisuje efekty jego działania po każdym wywołaniu polecenia
SQL. Domyślnie wszystkie adaptery Zend_Db
działają w trybie auto-commit.
Można również bezpośrednio wskazać początek i koniec transakcji i w ten sposób
kontrolować ilość zapytań SQL jakie trafiają do zapisania (bądź
cofnięcia) jako pojedyncza operacja. Aby rozpocząć transakcję należy wywołać metodę
beginTransaction()
. Następujące po niej polecenia
SQL są wykonywane w kontekście wspólnej transakcji do momentu
zasygnalizowania jej końca.
Aby zakończyć transakcję należy użyć metody commit()
lub
rollBack()
.
Pierwsza z nich powoduje zapisanie zmian wynikających
z operacji przeprowadzonych w czasie transakcji.
Oznacza to, że efekty tych zmian będą
widoczne w wynikach zapytań wywołanych w ramach innych transakcji.
Metoda rollBack()
dokonuje odwrotnej operacji: cofa zmiany
dokonane podczas transakcji.
W efekcie wszystkie dane zmienione podczas transakcji zostają cofnięte do
wartości z momentu przed jej rozpoczęciem. Cofnięcie zmian jednej transakcji nie
ma wpływu na zmiany dokonane przez inną transakcję trwającą nawet w tym samym czasie.
Po skończonej transakcji Zend_Db_Adapter
wraca
do trybu auto-commit do momentu ponownego wywołania metody
beginTransaction()
i ręcznego
rozpoczęcia nowej transakcji.
Przykład 216. Kontrolowanie transakcjami dla zachowania spójności
// Ręczne rozpoczęcie transakcji $db->beginTransaction(); try { // Próba wywołania jednego bądź wielu zapytań: $db->query(...); $db->query(...); $db->query(...); // Jeśli wszystkie odniosły sukces - zapisanie transakcji, dzięki czemu wszystkie rezultaty // zostaną zapisane za jednym razem. $db->commit(); } catch (Exception $e) { // Jeśli któreś z zapytań zakończyło się niepowodzeniem i został wyrzucony wyjątek, należy // cofnąć całą transakcję odwracając zmiany w niej dokonane (nawet te które zakończyły się // sukcesem). Przez to albo wszystkie zmiany zostają zapisane albo żadna. $db->rollBack(); echo $e->getMessage(); }
Metoda listTables()
zwraca tablicę łańcuchów znakowych,
zawierającą wszystkie tabele w bieżącej bazie danych.
Metoda describeTable()
zwraca tablicę asocjacyjną metadanych
tabeli. Jako argument należy podać nazwę tabeli.
Drugi argument jest opcjonalny - wskazuje
nazwę schematu w którym tabela się znajduje.
Kluczami zwracanej tablicy asocjacyjnej są nazwy kolumn tabeli. Wartość przy każdej kolumnie to następna tablica asocjacyjna z następującymi kluczami i wartościami:
Tabela 61. Metadane zwracane przez describeTable()
Klucz | Typ | Opis |
---|---|---|
SCHEMA_NAME |
(string) | Nazwa schematu bazy danych, w którym tabela się znajduje. |
TABLE_NAME |
(string) | Nazwa tabeli zawierającej daną kolumnę. |
COLUMN_NAME |
(string) | Nazwa kolumny. |
COLUMN_POSITION |
(integer) | Liczba porządkowa wskazująca na miejsce kolumny w tabeli. |
DATA_TYPE |
(string) | Nazwa typu danych dozwolonych w kolumnie. |
DEFAULT |
(string) | Domyślna wartość kolumny (jeśli istnieje). |
NULLABLE |
(boolean) |
TRUE jeśli columna dopuszcza wartości
SQL
NULL , FALSE
jeśli kolumna zawiera
ograniczenie NOT NULL .
|
LENGTH |
(integer) | Dopuszczalny rozmiar kolumny, w formie zgłoszonej przez serwer bazy danych. |
SCALE |
(integer) |
Skala typów SQL NUMERIC lub
DECIMAL .
|
PRECISION |
(integer) |
Precyzja typów SQL NUMERIC
lub DECIMAL .
|
UNSIGNED |
(boolean) |
TRUE jeśli typ danych liczbowych ma klauzulę
UNSIGNED .
|
PRIMARY |
(boolean) |
TRUE jeśli kolumna jest częścią
klucza pierwotnego tabeli.
|
PRIMARY_POSITION |
(integer) | Liczba porządkowa (min. 1) oznaczająca pozycję kolumny w kluczu pierwotnym. |
IDENTITY |
(boolean) |
TRUE jeśli kolumna korzysta
z wartości automatycznie generowanych.
|
Pole metadanych IDENTITY w różnych systemach zarządzania bazą danych
Pole metadanych IDENTITY zostało wybrane jako ogólny termin określający relację do klucza tabeli. Może być znany pod następującymi nazwami:
-
IDENTITY
- DB2, MSSQL -
AUTO_INCREMENT
- MySQL -
SERIAL
- PostgreSQL -
SEQUENCE
- Oracle
Jeśli w bazie danych nie istnieje tabela i schemat o podanych nazwach to
describeTable()
zwraca pustą tablicę.
Najczęściej nie ma potrzeby zamykać połączenia z bazą danych. PHP automatycznie czyści wszystkie zasoby pod koniec działania. Rozszerzenia bazy danych są zaprojektowane w taki sposób aby połączenie zostało zamknięte w momencie usunięcia referencji do obiektu zasobu.
Jednak w przypadku skryptu PHP, którego czas wykonania jest znaczący,
który inicjuje wiele połączeń z bazą danych, może zajść potrzeba
ręcznego zamknięcia połączenia aby ograniczyć wykorzystanie
zasobów serwera bazy danych. Aby wymusić zamknięcie połączenia
z bazą danych należy użyć metody adaptera closeConnection()
.
Od wersji 1.7.2 istnieje możliwość sprawdzenia czy w obecnej chwili
połączenie z serwerem bazy danych występuje za pomocą metody
isConnected()
.
Jej rezultat oznacza czy zasób połączenia został ustanowiony i nie został zamknięty.
Ta metoda nie jest zdolna sprawdzić zamknięcia połączenia od strony
serwera bazy danych.
Dzięki użyciu jej w wewnętrznych metodach zamykających połączenie
można dokonywać wielokrotnego zamknięcia połączenia bez ryzyka wystąpienia błędów.
Przed wersją 1.7.2 było to możliwe jedynie w
przypadku adapterów PDO.
Czy Zend_Db wspiera połączenia trwałe (Persistent Connections)?
Tak, trwałe połączenia są wspierane poprzez flagę persistent
ustawioną na wartość TRUE
w konfiguracji
adaptera Zend_Db
(a nie sterownika bazy danych).
Przykład 218. Użycie flagi stałego połączenia z adapterem Oracle
$db = Zend_Db::factory('Oracle', array( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test', 'persistent' => true ));
Należy zwrócić uwagę, że używanie połączeń stałych może zwiększyć ilość nieużywanych połączeń na serwerze bazy danych. Przez to, korzyści w wydajności (wynikające z wykluczenia potrzeby nawiązywania połączenia przy każdym żądaniu) mogą zostać skutecznie przeważone przez problemy spowodowane przez tą technikę.
Połączenia z bazą danych mają stany. Oznacza to, że pewne obiekty na serwerze bazy danych istnieją w kontekście sesji. Chodzi o blokady, zmienne użytkownika, tabele tymczasowe, informacje o ostatnio wykonanym zapytaniu - takie jak ilość pobranych wierszy, ostatnia wygenerowana wartość identyfikatora. W przypadku użycia połączeń stałych istnieje ryzyko, że aplikacja uzyska dostęp do niepoprawnych bądź zastrzeżonych danych, które zostały utworzone podczas poprzedniego żądania.
W obecnym stanie jedynie adaptery Oracle, DB2 oraz PDO
(zgodnie z dokumentacją PHP) wspierają połączenia stałe
w Zend_Db
.
Podczas tworzenia kodu może zajść potrzeba uzyskania dostępu bezpośrednio do
obiektu połączenia tak jak udostępnia to używane rozszerzenie bazy danych
PHP. Niektóre rozszerzenia mogą oferować funkcje nieodzwierciedlone
w metodach klasy Zend_Db_Adapter_Abstract
.
Wszystkie polecenia SQL w Zend_Db
są wywoływane poprzez instrukcje preparowane (prepared statement). Jednak niektóre
funkcje bazy danych są z nimi niekompatybilne. Polecenia DDL takie
jak CREATE czy ALTER nie mogą być wywoływane w ten sposób w MySQL. Dodatkowo polecenia
SQL nie korzystają z
cache'u zapytań
MySQL (MySQL Query Cache) dla wersji wcześniejszej niż MySQL 5.1.17.
Większość rozszerzeń baz danych PHP umożliwia wywoływanie poleceń
SQL bez preparowania. W przypadku PDO jest to
możliwe poprzez metodę exec()
. Aby uzyskać dostęp do obiektu
połączenia odpowiedniego rozszerzenia PHP należy wywołać metodę
getConnection()
.
Przykład 219. Wywołanie polecenia niepreparowanego dla adaptera PDO
$result = $db->getConnection()->exec('DROP TABLE bugs');
W podobny sposób można korzystać z innych metod szczególnych dla konkretnego rozszerzenia PHP. Należy jednak mieć w pamięci, iż w ten sposób ogranicza się tworzoną aplikację do współpracy z interfejsem oferowanym jedynie przez konkretne rozszerzenie konkretnej bazy danych.
W przyszłych wersjach Zend_Db
planowane jest umieszczanie
dodatkowych metod służących do obejmowania funkcjonalności wspólnych dla wielu
rozszerzeń baz danych PHP ale wsteczna kompatybilność zostanie
zachowana.
Począwszy od wersji 1.7.2 można pobrać wersję serwera bazy danych w formie podobnej do
numeru wersji PHP tak aby można było skorzystać z funkcji
version_compare()
. Jeśli taka informacja nie jest dostępna
to zostanie zwrócona wartość NULL
.
Przykład 220. Weryfikacja wersji serwera przed wywołaniem zapytania
$version = $db->getServerVersion(); if (!is_null($version)) { if (version_compare($version, '5.0.0', '>=')) { // wykonanie zapytania } else { // wykonanie innego zapytania } } else { // wersja serwera niedostępna }
Ten akapit wymienia różnice pomiędzy klasami adapterów, z istnienia których należy sobie zdawać sprawę.
-
Aby uzyskać ten adapter poprzez metodę
factory()
należy użyć nazwy 'Db2'. -
Ten adapter używa rozszerzenia PHP ibm_db2.
-
IBM DB2 wspiera sekwencje oraz klucze automatycznie zwiększające. Przez to argumenty dla
lastInsertId()
są opcjonalne. Jeśli nie poda się argumentów adapter zwróci ostatnią wartość wygenerowaną dla klucza automatycznego. Jeśli argumenty zostaną podane to adapter zwróci ostatnią wartość wygenerowaną przez sekwencję o nazwie zgodnej z konwencją 'tabela_kolumna_seq'.
-
Aby uzyskać ten adapter poprzez metodę
factory()
należy użyć nazwy 'Mysqli'. -
Ten adapter używa rozszerzenia PHP mysqli.
-
MySQL nie wspiera sekwencji więc
lastInsertId()
ignoruje argumenty i zwraca ostatnią wartość wygenerowaną dla klucza automatycznego. MetodalastSequenceId()
zwracaNULL
.
-
Aby uzyskać ten adapter poprzez metodę
factory()
należy użyć nazwy 'Oracle'. -
Ten adapter używa rozszerzenia PHP oci8.
-
Oracle nie wspiera kluczy automatycznych więc należy podać nazwę sekwencji w metodzie
lastInsertId()
lublastSequenceId()
. -
Rozszerzenie Oracle nie wspiera parametrów pozycyjnych. Należy używać nazwanych parametrów.
-
Obecnie, opcja
Zend_Db::CASE_FOLDING
nie jest zaimplementowana w tym adapterze. Aby użyć tej opcji z Oracle zalecane jest korzystanie z adaptera PDO OCI. -
Domyślnie pola LOB są zwracane jako obiekty OCI-Lob. Można ustawić pobieranie ich w formie łańcuchów znakowych dla wszystkich żądań poprzez opcję sterownika 'lob_as_string'. Aby jednorazowo pobrać obiekt Lob jako string należy użyć metody
setLobAsString(boolean)
na adapterze lub na obiekcie zapytania.
-
Aby uzyskać ten adapter poprzez metodę
factory()
należy użyć nazwy 'Sqlsrv'. -
Ten adapter używa rozszerzenia PHP sqlsrv.
-
Microsoft SQL Server nie wspiera sekwencji więc
lastInsertId()
ignoruje argument określający klucz pierwotny i zwraca ostatnią wartość wygenerowaną przez automatyczny klucz (jeśli jest podana nazwa tabeli) lub identyfikator zwrócony przez ostatnie polecenie INSERT. MetodalastSequenceId()
zwracaNULL
. -
Zend_Db_Adapter_Sqlsrv
ustawia opcjęQUOTED_IDENTIFIER ON
bezpośrednio po połączeniu się z bazą danych SQL Server. To powoduje, że sterownik zaczyna używać standardowego znaku cudzysłowu (") jako ograniczenia identyfikatorów zamiast - charakterystycznych dla produktu Microsoftu - nawiasów kwadratowych. -
Jednym z kluczy podawanych do tablicy opcji może być driver_options dzięki czemu można skorzystać z wartości podanych w dokumentacji SQL Server http://msdn.microsoft.com/en-us/library/cc296161(SQL.90).aspx.
-
Dzięki metodzie
setTransactionIsolationLevel()
można ustawić poziom izolacji transakcji dla bieżącego połączenia. Rozpoznawane wartości toSQLSRV_TXN_READ_UNCOMMITTED
,SQLSRV_TXN_READ_COMMITTED
,SQLSRV_TXN_REPEATABLE_READ
,SQLSRV_TXN_SNAPSHOT
orSQLSRV_TXN_SERIALIZABLE
. -
Począwszy od Zend Framework 1.9 minimalną wspieraną wersją rozszerzenia PHP Microsoft SQL Server jest 1.0.1924.0. a dla MSSQL Server Native Client - wersja 9.00.3042.00.
-
Aby uzyskać ten adapter poprzez metodę
factory()
należy użyć nazwy 'Pdo_Ibm
'. -
Ten adapter używa rozszerzeń PHP pdo and pdo_ibm.
-
Należy używać wersji 1.2.2 lub wyższej rozszerzenia PDO_IBM. Zaleca się uaktualnienie wcześniejszych wersji poprzez PECL.
-
Aby uzyskać ten adapter poprzez metodę
factory()
należy użyć nazwy 'Pdo_Mssql
'. -
Ten adapter używa rozszerzeń PHP pdo and pdo_dblib.
-
Microsoft SQL Server nie wspiera sekwencji więc
lastInsertId()
ignoruje argument określający klucz pierwotny i zwraca ostatnią wartość wygenerowaną przez automatyczny klucz (jeśli jest podana nazwa tabeli) lub identyfikator zwrócony przez ostatnie polecenie INSERT. MetodalastSequenceId()
zwracaNULL
. -
W przypadku pracy z łańcuchami znaków unicode zakodowanych w sposób inny niż UCS-2 (czyli również w formie UTF-8), może zajść potrzeba dokonania konwersji w kodzie aplikacji lub przechowywania danych w kolumnach binarnych. Aby uzyskać więcej informacji można skorzystać z Microsoft's Knowledge Base.
-
Zend_Db_Adapter_Pdo_Mssql
ustawia opcjęQUOTED_IDENTIFIER ON
bezpośrednio po połączeniu się z bazą danych SQL Server. To powoduje, że sterownik zaczyna używać standardowego znaku cudzysłowu (") jako ograniczenia identyfikatorów zamiast - charakterystycznych dla produktu Microsoftu - nawiasów kwadratowych. -
Adapter rozpoznaje klucz pdoType w tablicy opcji. Jego wartość może wynosić "mssql" (domyślnie), "dblib", "freetds", lub "sybase". To wpływa na prefiks DSN używany przez adapter do utworzenia łańcucha połączenia. Wartości "freetds" oraz "sybase" powodują utworzenie prefiksu "sybase:" używanego przez biblioteki FreeTDS. Należy zapoznać się z informacjami dotyczącymi prefiksów DSN używanymi przez ten sterownik pod adresem http://www.php.net/manual/en/ref.pdo-dblib.connection.php
-
Aby uzyskać ten adapter poprzez metodę
factory()
należy użyć nazwy 'Pdo_Mysql
'. -
Ten adapter używa rozszerzeń PHP pdo and pdo_mysql.
-
MySQL nie wspiera sekwencji więc
lastInsertId()
ignoruje argumenty i zwraca ostatnią wartość wygenerowaną dla klucza automatycznego. MetodalastSequenceId()
zwracaNULL
.
-
Aby uzyskać ten adapter poprzez metodę
factory()
należy użyć nazwy 'Pdo_Oci
'. -
Ten adapter używa rozszerzeń PHP pdo and pdo_oci.
-
Oracle nie wspiera kluczy automatycznych więc należy podać nazwę sekwencji w metodzie
lastInsertId()
lublastSequenceId()
.
-
Aby uzyskać ten adapter poprzez metodę
factory()
należy użyć nazwy 'Pdo_Pgsql
'. -
Ten adapter używa rozszerzeń PHP pdo and pdo_pgsql.
-
PostgreSQL wspiera sekwencje oraz klucze automatyczne. Przez to podawanie argumentów w
lastInsertId()
jest opcjonalne. Jeśli nie poda się argumentów adapter zwróci ostatnią wartość wygenerowaną dla klucza automatycznego. Jeśli argumenty zostaną podane to adapter zwróci ostatnią wartość wygenerowaną przez sekwencję o nazwie zgodnej z konwencją 'tabela_kolumna_seq'.
-
Aby uzyskać ten adapter poprzez metodę
factory()
należy użyć nazwy 'Pdo_Sqlite
'. -
Ten adapter używa rozszerzeń PHP pdo and pdo_sqlite.
-
SQLite nie wspiera sekwencji więc
lastInsertId()
ignoruje argumenty i zwraca ostatnią wartość wygenerowaną dla klucza automatycznego. MetodalastSequenceId()
zwracaNULL
. -
Aby połączyć się z bazą danych SQLite2 należy podać 'sqlite2' => true jako jeden z elementów tablicy parametrów podczas tworzenia instancji adaptera
Pdo_Sqlite
. -
Aby połączyć się z bazą danych SQLite rezydującą w pamięci należy podać 'dbname' => ':memory:' jako jeden z elementów tablicy parametrów podczas tworzenia instancji adaptera
Pdo_Sqlite
. -
Starsze wersje sterownika PHP SQLite nie wspierają poleceń PRAGMA niezbędnych dla zachowania krótkich nazw kolumn w wynikach zapytania. W przypadku wystąpienia problemów z zapytaniami JOIN polegających na zwracaniu wyników z nazwami kolumn w postaci "tabela.kolumna" zaleca się aktualizację PHP do najnowszej wersji.
-
Ten adapter używa rozszerzenia PHP php_interbase.
-
Firebird/Interbase nie wspiera kluczy automatycznych więc należy podać nazwę sekwencji w metodzie
lastInsertId()
lublastSequenceId()
. -
Obecnie, opcja
Zend_Db::CASE_FOLDING
nie jest zaimplementowana w tym adapterze. Identyfikatory bez znaków ograniczających są zwracane w postaci wielkich liter. -
Nazwa adaptera to
ZendX_Db_Adapter_Firebird
.Należy pamiętać o użyciu parametru adapterNamespace z wartością
ZendX_Db_Adapter
.Zaleca się aktualizację pliku
gds32.dll
(lub odpowiednika wersji linux) dostarczanym z PHP do wersji odpowiadającej serwerowi bazy danych. Dla Firebird odpowiednikiemgds32.dll
jestfbclient.dll
.Domyślnie wszystkie identyfikatory (nazwy tabel, kolumn) są zwracane wielkimi literami.