Pripremljeni upiti pdo. MySQL dodatne funkcije. Načini prikupljanja podataka

Većina baza podataka podržava koncept pripremljenih upita. Šta je to? Ovo se može opisati kao neka vrsta kompajliranog predloška SQL upita koji će pokrenuti aplikacija i konfigurirati pomoću ulaznih parametara. Pripremljeni upiti imaju dvije glavne prednosti:

  • Zahtjev se mora pripremiti jednom, a zatim se može pokrenuti onoliko puta koliko je potrebno, sa istim i različitim parametrima. Kada je upit pripremljen, DBMS ga analizira, kompajlira i optimizira njegov plan izvršenja. Za složene upite, ovaj proces može potrajati značajno vrijeme i može značajno usporiti aplikaciju ako trebate pokrenuti upit više puta s različitim parametrima. Kada se koristi pripremljeni upit, DBMS samo jednom analizira/kompilira/optimizira upit bilo koje složenosti, a aplikacija pokreće već pripremljeni predložak za izvršenje. Na ovaj način pripremljeni upiti troše manje resursa i rade brže.
  • Pripremljeni parametri upita ne moraju biti zaklonjeni navodnicima; vozač to radi automatski. Ako aplikacija koristi isključivo pripremljene upite, programer može biti siguran da se SQL injekcija ne može dogoditi (međutim, ako su drugi dijelovi tijela upita napisani znakovima bez preseka, SQL injekcija je i dalje moguća; ovdje mi pričamo o tome konkretno o parametrima).

Pripremljeni upiti su također korisni jer ih PDO može emulirati ako upravljački program baze podataka nema sličnu funkcionalnost. To znači da aplikacija može koristiti istu tehniku ​​pristupa podacima bez obzira na mogućnosti DBMS-a.

Primjer #1 Ponovljeno umetanje u bazu podataka korištenjem pripremljenih upita

ime I vrijednost, koje se zamjenjuju umjesto odgovarajućih pseudo-varijabli:

$stmt = $dbh -> pripremiti ( "UMETNI U REGISTAR (ime, vrijednost) VRIJEDNOSTI (:ime, :vrijednost)");
$stmt -> bindParam (":name" , $name );
$stmt -> bindParam (":value" , ​​$value);

// umetnuti jedan red
$name = "jedan" ;
$value = 1;
$stmt -> izvršiti();

$name = "dva" ;
$value = 2 ;
$stmt -> izvršiti();
?>

Primjer #2 Ponovljeno umetanje u bazu podataka korištenjem pripremljenih upita

U ovom primjeru, INSERT upit se izvršava 2 puta sa različita značenja ime I vrijednost koje se zamjenjuju umjesto pseudo-varijabli ? .

$stmt = $dbh -> pripremiti ( "UMETNI U REGISTAR (ime, vrijednost) VRIJEDNOSTI (?, ?)");
$stmt -> bindParam(1, $name);
$stmt -> bindParam (2, $vrijednost);

// umetnuti jedan red
$name = "jedan" ;
$value = 1;
$stmt -> izvršiti();

// sada još jedan red s različitim vrijednostima
$name = "dva" ;
$value = 2 ;
$stmt -> izvršiti();
?>

Primjer #3 Dohvaćanje podataka korištenjem pripremljenih upita

U ovom primjeru, odabir se vrši iz baze podataka pomoću ključa koji korisnik unosi kroz obrazac. Korisnički unos se automatski navodi, tako da nema rizika od SQL injekcije.

Ako DBMS podržava izlazne parametre, aplikacija ih može koristiti na isti način kao i ulazne. Izlazni parametri se obično koriste za dohvaćanje podataka iz pohranjenih procedura. Korištenje izlaznih parametara je nešto teže, jer programer mora znati maksimalnu veličinu ekstrahiranih vrijednosti u fazi postavljanja ovih parametara. Ako je dohvaćena vrijednost veća od očekivane, pojavit će se greška.

Primjer #4 Pozivanje pohranjene procedure s izlaznim parametrima

$stmt = $dbh -> pripremi ("POZOVI sp_returns_string(?)" );
$stmt -> bindParam(1, $return_value, PDO::PARAM_STR, 4000);

// pozivanje pohranjene procedure
$stmt -> izvršiti();

print "procedura se vratila$return_value \n" ;
?>

Možete postaviti parametar da bude i ulaz i izlaz; Sintaksa je ista kao i za izlazne parametre. Sljedeći primjer prosljeđuje string "zdravo" pohranjenoj proceduri, a zatim će string biti zamijenjen povratnom vrijednošću.

Primjer #5 Pozivanje pohranjene procedure s ulazno/izlaznim parametrom

$stmt = $dbh -> pripremiti ( "POZOVITE sp_takes_string_returns_string(?)");
$value = "zdravo" ;!}
$stmt -> bindParam (1, $value, PDO :: PARAM_STR | PDO :: PARAM_INPUT_OUTPUT, 4000);

// pozivanje pohranjene procedure
$stmt -> izvršiti();

print "procedura se vratila$value\n" ;
?>

(niz("% $_GET [ime] %" ));
?>










PDO ima svoju pametnu metodu povezivanja koja se zove . Plus, tokom konekcije možete postaviti gomilu opcija, od kojih su neke izuzetno korisne. Potpuna lista se može pronaći, ali samo neke su važne.

Primjer ispravne veze:

$host = "127.0.0.1" ;
$db = "test" ;
$user = "root" ;
$pass = "" ;
$charset = "utf8" ;

$dsn = "mysql:host= $host ;dbname= $db ;charset= $charset ";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => lažno,
];
$pdo = novi PDO ($dsn, $user, $pass, $opt);

sta se desava ovde?

$dsn specificira tip baze podataka sa kojom ćemo raditi (mysql), host, ime baze podataka i charset.
- slijedi korisničko ime i lozinka
- nakon čega se navodi niz opcija, o čemu ne piše ni u jednom priručniku.

Unatoč činjenici da je ovaj niz izuzetno korisna stvar, kao što je gore spomenuto. Najvažnije je da se način greške postavlja samo u obliku izuzetaka.
- Prvo, zato što u svim ostalim načinima PDO ne prijavljuje ništa razumljivo o grešci,
- drugo, jer izuzetak uvijek sadrži nezamjenjiv trag steka,
- treće, izuzeci su izuzetno zgodni za rukovanje.

Osim toga, vrlo je zgodno postaviti FETCH_MODE po defaultu kako ga ne biste pisali u SVAKOM zahtjevu, kao što marljivi hrčci vole da rade.
Također ovdje možete podesiti pconnect mod, emulaciju pripremljenih izraza i mnoge druge strašne riječi.

Kao rezultat, dobijamo varijablu $pdo, s kojom radimo kroz cijelu skriptu.

Možete koristiti dvije metode za izvršavanje upita.
Ako nijedna varijabla nije proslijeđena zahtjevu, tada možete koristiti funkciju query(). On će izvršiti zahtjev i vratiti poseban objekt - PDO naredbu. Vrlo grubo, možete ga uporediti sa mysql resursom, koji je vratio mysql_query(). Možete dobiti podatke iz ovog objekta na tradicionalan način, kroz while ili kroz foreach(). Također možete zatražiti vraćanje primljenih podataka u posebnom formatu, o čemu se govori u nastavku.
$stmt = $pdo -> upit ("SELECT name FROM users" );
dok ($red = $stmt -> dohvati())
{
}

Ako je barem jedna varijabla proslijeđena zahtjevu, onda se ovaj zahtjev mora izvršiti samo kroz pripremljene izraze. Šta je to? Ovo je običan SQL upit, u kojem se umjesto varijable postavlja poseban marker - čuvar mjesta. PDO podržava pozicione čuvare mjesta (?), za koje je redoslijed proslijeđenih varijabli važan, i imenovane čuvare mjesta (:name), za koje redoslijed nije važan. primjeri:
$sql = ;
$sql = ;

Da biste izvršili takav upit, on se prvo mora pripremiti pomoću funkcije pripreme(). Također vraća PDO izjavu, ali još bez ikakvih podataka. Da biste ih dobili, morate izvršiti ovaj zahtjev, nakon što ste prethodno u njega prenijeli varijable. Možete ga prenijeti na dva načina:
Najčešće možete jednostavno izvršiti metodu execute() i proslijediti joj niz varijabli:
$stmt = $pdo -> pripremi ( "IZABERI ime OD korisnika GDJE email = ?");
$stmt -> izvršiti (niz($email));

$stmt = $pdo -> pripremi ( "IZABERITE ime OD korisnika GDJE email = :email");
$stmt -> izvršiti (array("email" => $email ));
Kao što vidite, u slučaju imenovanih čuvara mjesta, niz u kojem ključevi moraju odgovarati imenima čuvara mjesta mora biti proslijeđen funkciji execute().

Ponekad, vrlo rijetko, može biti potrebna druga metoda, kada se varijable prvo vezuju za zahtjev jedna po jedna, koristeći bindValue() / bindParam(), a zatim se samo izvršavaju. U ovom slučaju, ništa se ne prosljeđuje funkciji execute(). Primjer se može naći u priručniku.
Kada koristite ovu metodu, treba li uvijek preferirati bindValue()? jer ponašanje bindParam() nije očito početnicima i dovest će do problema.

Zatim možete koristiti PDO izjavu na isti način kao gore. Na primjer, preko foreach-a:
$stmt = $pdo -> pripremi ( "IZABERI ime OD korisnika GDJE email = ?");
$stmt ->
foreach ($stmt kao $red)
{
echo $row [ "name" ] . "\n" ;
}

BITAN: Pripremljeni izrazi su glavni razlog za korištenje PDO jer je jedini siguran način izvršavanje SQL upita koji uključuju varijable.

Takođe, preparat() / execute() se može koristiti za uzastopno izvršavanje jednom pripremljenog upita sa različitim skupovima podataka. U praksi je to potrebno izuzetno rijetko i ne donosi mnogo povećanja brzine. Ali u slučaju da trebate napraviti mnogo upita istog tipa, možete to napisati ovako:

$data = niz(
1 => 1000,
5 => 300,
9 => 200,
);

$stmt = $pdo -> pripremi ( "AŽURIRAJTE korisnike SET bonus = bonus + ? WHERE id = ?");
foreach ($data kao $id => $bonus)
{
$stmt -> izvršiti ([ $bonus, $id ]);
}

Ovdje pripremamo zahtjev jednom, a zatim ga izvršavamo više puta.

Već smo se upoznali sa metodom fetch(), koja se koristi za sekvencijalno dobijanje redova iz baze podataka. Ova metoda je analogna funkciji mysq_fetch_array() i sličnim, ali djeluje drugačije: umjesto mnogih funkcija ovdje se koristi jedna, ali njeno ponašanje je specificirano proslijeđenim parametrom. O ovim parametrima ću detaljno pisati kasnije, ali kao kratku preporuku preporučio bih korištenje fetch() u FETCH_LAZY modu:
$stmt = $pdo -> pripremi ( "IZABERI ime OD korisnika GDJE email = ?");
$stmt -> execute([ $_GET [ "e-pošta" ]]);
dok ($red = $stmt -> dohvati (PDO :: FETCH_LAZY ))
{
echo $row [ 0 ] . "\n" ;
echo $row [ "name" ] . "\n" ;
echo $red -> ime . "\n" ;
}

U ovom načinu rada ne gubi se dodatna memorija, a osim toga, stupcima se može pristupiti na bilo koji od tri načina - preko indeksa, imena ili svojstva.

PDO izraz također ima pomoćnu funkciju za dobivanje vrijednosti jednog stupca. Vrlo je zgodno ako tražimo samo jedno polje - u ovom slučaju se količina pisanja značajno smanjuje:
$stmt = $pdo -> pripremi ( "SELECT name FROM table WHERE id=?");
$stmt -> izvršiti (niz($id));
$name = $stmt -> fetchColumn();

Ali najzanimljivija funkcija, sa najvećom funkcionalnošću, je fetchAll(). To je ono što PDO čini bibliotekom visokog nivoa za rad sa bazom podataka, a ne samo drajverom niskog nivoa.

FetchAll() vraća niz koji se sastoji od svih redova koje je upit vratio. Iz čega se mogu izvući dva zaključka:
1. Ovu funkciju ne treba koristiti kada upit vraća puno podataka. U ovom slučaju, bolje je koristiti tradicionalnu petlju sa fetch()
2. Budući da se u modernim PHP aplikacijama podaci nikada ne izlaze odmah po prijemu, već se prenose u šablon za tu svrhu, fetchAll() postaje jednostavno nezamjenjiv, omogućavajući vam da izbjegnete ručno pisanje petlji, a samim tim i smanjite količinu koda.

Dobivanje jednostavnog niza.
Pozvana bez parametara, ova funkcija vraća regularni indeksirani niz koji sadrži redove iz baze podataka, u formatu specificiranom u FETCH_MODE po defaultu. Konstante PDO::FETCH_NUM, PDO::FETCH_ASSOC, PDO::FETCH_OBJ mogu promijeniti format u hodu.

Dobivanje kolone.
Ponekad trebate dobiti jednostavan jednodimenzionalni niz tražeći jedno polje iz gomile nizova. Da biste to učinili, koristite način rada PDO::FETCH_COLUMN
$data = $pdo -> upit ("SELECT name FROM users" ) -> fetchAll (PDO :: FETCH_COLUMN);
niz (
0 => "Jovan" ,
1 => "Mike" ,
2 => "Marija" ,
3 => "Kathy" ,
)

Dohvaćanje parova ključ/vrijednost.
Takođe popularan format kada je poželjno dobiti istu kolonu, ali indeksiranu ne brojevima, već jednim od polja. Za to je odgovorna konstanta PDO::FETCH_KEY_PAIR.
$data = $pdo -> upit ("SELECT id, name FROM users" ) -> fetchAll (PDO :: FETCH_KEY_PAIR);
niz (
104 => "Jovan" ,
110 => "Mike" ,
120 => "Marija" ,
121 => "Kathy" ,
)

Dobiti sve redove indeksirane poljem.
Takođe je često potrebno dobiti sve redove iz baze podataka, ali i indeksirane ne brojevima, već jedinstvenim poljem. Konstanta PDO::FETCH_UNIQUE to radi.
$data = $pdo -> upit ("SELECT * FROM users") -> fetchAll (PDO :: FETCH_UNIQUE );
niz (
104 => niz (
"name" => "Jovan" ,
"auto" => "Toyota" ,
),
110 => niz (
"name" => "Mike" ,
"auto" => "Ford" ,
),
120 => niz (
"name" => "Mary" ,
"auto" => "Mazda" ,
),
121 => niz (
"name" => "Kathy" ,
"auto" => "Mazda" ,
),
)

Treba imati na umu da prvo morate odabrati jedinstveno polje u koloni.

Postoji više od jednog i pol tuceta različitih načina akvizicije podataka u PDO. Osim toga, možete ih kombinirati! Ali ovo je tema za poseban članak.

Kada radite sa pripremljenim izrazima, trebali biste razumjeti da čuvar mjesta može zamijeniti samo niz ili broj. Ni jedno ni drugo ključna riječ, ni identifikator, ni dio niza ili skup nizova ne mogu se zamijeniti rezerviranim mjestom. Stoga, za LIKE morate prvo pripremiti cijeli niz za pretraživanje, a zatim ga zamijeniti u upit:

$name = "% $name %" ;
$stm = $pdo -> pripremi ( "SELECT * FROM table WHERE ime LIKE?");
$stm -> izvršiti (niz($name));
$data = $stm -> fetchAll();

Pa, shvatili ste. I ovdje je sve loše. PDO uopće ne pruža nikakve alate za rad sa identifikatorima, te se moraju formatirati na starinski način, ručno (ili, ipak, gledati prema SafeMysql-u, u kojem je ovo, kao i mnoga druga pitanja, riješeno jednostavno i elegantno).
Treba imati na umu da se pravila za formatiranje identifikatora razlikuju za različite baze podataka.

U mysql-u, da biste ručno formatirali identifikator, trebate učiniti dvije stvari:
- stavite ga u pozadinske kvačice ("`").
- potražite ove znakove unutar identifikatora udvostručavanjem.

$field = "`" . str_replace ("`" , "``" , $_GET [ "field" ]). "`" ;
$sql = $polje ";

Međutim, ovdje postoji jedno upozorenje. Samo formatiranje možda neće biti dovoljno. Gornji kod nas štiti od klasične injekcije, ali u nekim slučajevima neprijatelj i dalje može napisati nešto neželjeno ako nepromišljeno zamijenimo imena polja i tablica direktno u upit. Na primjer, u tabeli korisnika postoji admin polje. Ako nazivi dolaznih polja nisu filtrirani, onda će svaka budala upisati bilo kakve gadne stvari u ovo polje kada automatski generira zahtjev iz POST-a.

Stoga je preporučljivo provjeriti valjanost imena tabela i polja koja dolaze od korisnika, kao u primjeru ispod

Svaki embed kod koji se može vidjeti u brojnim tutorijalima donosi melanholiju i želju da se ubije apsten. Višekilometarske konstrukcije sa ponavljanjem istih imena - u $_POST indeksima, u imenima varijabli, u imenima polja u zahtjevu, u imenima čuvara mjesta u zahtjevu, u imenima čuvara mjesta i imenima varijabli prilikom povezivanja.
Gledajući ovaj kod, poželim da nekoga ubijem, ili ga barem malo skratim.

Ovo se može učiniti usvajanjem konvencije da se imena polja u obrascu podudaraju s imenima polja u tabeli. Tada se ova imena mogu navesti samo jednom (radi zaštite od zamjene, što je gore spomenuto), a za sastavljanje upita može se koristiti mala pomoćna funkcija, koja je, zbog specifičnosti mysql-a, pogodna i za INSERT i za UPDATE upiti:

funkcija pdoSet ($allowed, & $values, $source = array()) (
$set = "" ;
$values ​​= niz();
if (! $source ) $source = & $_POST;
foreach ($ dozvoljeno kao $field) (
if (isset($source [ $field ])) (
$set .= "`" . str_replace ("`" , "``" , $field). "`". "=: $field, ";
$values ​​[ $field ] = $source [ $field ];
}
}
return substr ($set, 0, - 2);
}

U skladu s tim, embed kod će biti

$allowed = array("ime" , "prezime" , "e-pošta"); // dozvoljena polja
$sql = "INSERT INTO users SET " . pdoSet ($dozvoljeno, $vrijednosti);
$stm = $dbh -> pripremiti ($sql);
$stm -> izvršiti ($vrijednosti);

A za ažuriranje - ovo:

$allowed = array("name" , "prezime" , "email" , "password" ); // dozvoljena polja
$_POST ["password" ] = MD5 ($_POST [ "login" ]. $_POST [ "password" ]);
$sql = "AŽURIRAJ PODEŠAVANJE korisnika " . pdoSet ($dozvoljeno, $vrijednosti). "WHERE id = :id" ;
$stm = $dbh -> pripremiti ($sql);
$values ​​["id" ] = $_POST ["id"];
$stm -> izvršiti ($vrijednosti);

Nije baš impresivno, ali veoma efektno. Uzgred da vas podsjetim da ako koristite Class za siguran i praktičan rad sa MySQL-om, onda se to sve radi u dva reda.

PDO i ključne riječi
Nemoguće je smisliti nešto drugo osim filtriranja ovdje. Stoga je glupo pokrenuti sve operatore koji nisu direktno navedeni u zahtjevu kroz bijelu listu:

$dirs = array("ASC" , "DESC");
$key = array_search($_GET["dir"], $dirs));
$dir = $narudžbe [$ključ];
$sql = "ODABIR * IZ `tabela` ORDER BY$field $dir " ;

Termin PDO je skraćenica za koncept PHP objekti podataka. Kao što ime govori, ova tehnologija vam omogućava rad sa sadržajem baze podataka kroz objekte.

Zašto ne myqli ili mysql?

Najčešće se, kada se radi o novim tehnologijama, postavlja pitanje njihovih prednosti u odnosu na stare dobre i provjerene alate, kao i prijenos postojećih i starih projekata na njih.

Objektna orijentacija PDO

PHP Vrlo se aktivno razvija i nastoji da postane jedan od najboljih alata za brzi razvoj web aplikacija, kako na masovnom tako i na korporativnom nivou.

Pričamo o tome PHP, mislimo na moderan objektno orijentisan PHP, što vam omogućava da napišete univerzalni kod koji je pogodan za testiranje i ponovnu upotrebu.

Upotreba PDO omogućava vam da premjestite rad baze podataka na objektno orijentiranu razinu i poboljšate prenosivost koda. U stvari, upotreba PDO nije tako teško kao što se misli.

Apstrakcija

Zamislimo da već jesmo dugo vrijeme razvijamo aplikaciju koristeći MySQL. A onda, u jednom lijepom trenutku, postaje potrebno zamijeniti MySQL on PostgreSQL.

U najmanju ruku, morat ćemo zamijeniti sve pozive mysqli_connect() (mysql_connect()) on pg_connect() i, po analogiji, druge funkcije koje se koriste za upite i obradu podataka.

Koristeći PDO, ograničit ćemo se na promjenu nekoliko parametara u konfiguracijskim datotekama.

Vezivanje parametara

Korištenje povezanih parametara pruža veću fleksibilnost u dizajnu upita i poboljšava zaštitu od SQL injekcije.

Primanje podataka kao objekata

Oni koji već koriste ORM(objektno-relacijsko mapiranje - objektno-relacijsko mapiranje podataka), na primjer, Doktrina, poznaju pogodnost predstavljanja podataka iz tabela baze podataka u obliku objekata. PDO omogućava primanje podataka u obliku objekata i bez upotrebe ORM.

Mysql ekstenzija više nije podržana

Podrška za proširenje mysql trajno uklonjeno iz novog PHP 7. Ako planirate prenijeti projekat na nova verzija PHP, trebali biste sada koristiti barem mysqli u njemu. Naravno, bolje je početi koristiti PDO ako to već niste učinili.

Čini mi se da su ovi razlozi dovoljni da preokrenu vagu u korist upotrebe PDO. Štaviše, ne morate instalirati ništa dodatno.

Provjera prisustva PDO u sistemu

Verzije PHP 5.5 i viši, najčešće, već sadrže ekstenziju za rad PDO. Da provjerite, samo pokrenite jednostavnu naredbu u konzoli:

php -i | grep "pdo"

Sada ga otvorimo u bilo kojem pregledniku i pronađimo potrebne podatke pretraživanjem po redu PDO.

Upoznavanje sa PDO

Proces rada sa PDO ne razlikuje se previše od tradicionalnog. Općenito, proces korištenja PDO izgleda ovako:

  1. Povežite se sa bazom podataka;
  2. Ako je potrebno, pripremite zahtjev i parametre veze;
  3. Izvršavanje zahtjeva.

Povezivanje sa bazom podataka

Da biste se povezali sa bazom podataka potrebno je kreirati novi objekat PDO i proslijedite mu ime izvora podataka, također poznatog kao DSN.

Uglavnom, DSN sastoji se od imena drajvera odvojenog dvotočkom od niza veze specifičnog za svaki drajver PDO.

Za MySQL, veza se vrši ovako:

$connection = novi PDO("mysql:host=localhost;dbname=mydb;charset=utf8", "root", "root");

$connection = novi PDO ( "mysql:host=localhost;dbname=mydb;charset=utf8", "root" , "root" );

IN u ovom slučaju, DSN sadrži ime drajvera mysql, indikacija hosta (mogući format host=HOST_NAME:PORT), naziv baze podataka, kodiranje, korisničko ime MySQL i njegovu lozinku.

Zahtjevi

Za razliku od mysqli_query(), V PDO postoje dvije vrste zahtjeva:

  • Vraćanje rezultata ( izaberite, prikažite);
  • Ne vraća rezultat ( insert, detalj i drugi).

Prije svega, razmotrimo drugu opciju.

Izvršavanje upita

Pogledajmo primjer izvršavanja zahtjeva koristeći primjer insert.

$connection->exec("INSERT INTO korisničke VRIJEDNOSTI (1, "somevalue"");

$connection -> exec () ;

Naravno, ovaj upit vraća broj zahvaćenih redova i možete ga vidjeti na sljedeći način.

$affectedRows = $connection->exec("INSERT U korisničke VRIJEDNOSTI (1, "somevalue""); echo $affectedRows;

$affectedRows = $connection -> exec ( "INSERT U korisničke VRIJEDNOSTI (1, "neka vrijednost"") ;

echo $affectedRows ;

Dobivanje rezultata upita

U slučaju upotrebe mysqli_query(), kod bi mogao biti sljedeći.

$result = mysql_query("SELECT * FROM users"); while($row = mysql_fetch_assoc($result)) ( echo $row["id"] . " " . $row["name"]; )

$result = mysql_query ("SELECT * FROM users" ) ;

dok ($red = mysql_fetch_assoc ($rezult) ) (

Za PDO, kod će biti jednostavniji i sažetiji.

foreach($connection->query("SELECT * FROM users") kao $row) ( echo $row["id"] . " " . $row["name"]; )

foreach ($connection -> query ("SELECT * FROM users") kao $red ) (

echo $row [ "id" ] . " " . $row["name"];

Načini prikupljanja podataka

Kao u mysqli, PDO omogućava primanje podataka u različiti načini rada. Za određivanje načina rada, klase PDO sadrži odgovarajuće konstante.

  • PDO::FETCH_ASSOC— vraća niz indeksiran imenom kolone u tabeli baze podataka;
  • PDO::FETCH_NUM— vraća niz indeksiran brojem kolone;
  • PDO::FETCH_OBJ- vraća anonimni objekat sa imenima svojstava koja odgovaraju imenima kolona. Na primjer, $row->id će sadržavati vrijednost iz kolone id.
  • PDO::FETCH_CLASS— vraća novu instancu klase, sa vrijednostima svojstava koje odgovaraju podacima iz reda tabele. Ako je parametar specificiran PDO::FETCH_CLASSTYPE(Na primjer PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE), ime klase će se odrediti iz vrijednosti prve kolone.

Bilješka: nije puna lista, sve moguće konstante i opcije za njihovu kombinaciju dostupne su u dokumentaciji.

Primjer dobivanja asocijativnog niza:

$statement = $connection->query("SELECT * FROM users"); while($row = $statement->fetch(PDO::FETCH_ASSOC)) ( echo $row["id"] . " " . $row["name"]; )

$statement = $veza ->

dok ($red = $naredba -> dohvati (PDO::FETCH_ASSOC) ) (

echo $row [ "id" ] . " " . $row["name"];

Bilješka: Preporučuje se da uvijek navedete način uzorkovanja jer je način PDO::FETCH_BOTHće zahtijevati dva puta više memorije- ustvari će se kreirati dva niza, asocijativni i regularni.

Razmislite o korištenju načina uzorkovanja PDO::FETCH_CLASS. Hajde da napravimo klasu Korisnik:

klasa Korisnik ( zaštićen $id; zaštićeno $name; javna funkcija getId() (vrati $this->id; ) javna funkcija setId($id) ( $this->id = $id; ) javna funkcija getName() ( vrati $this->name; ) javna funkcija setName($name) ( $this->name = $name; ) )

class User

zaštićeni $id ;

zaštićeno $name ;

javna funkcija getId()

vrati $this -> id;

javna funkcija setId ($id)

$this -> id = $id;

javna funkcija getName()

vrati $this -> name ;

javna funkcija setName ($name)

$this -> name = $name ;

Sada odaberimo podatke i prikažimo podatke koristeći metode klase:

$statement = $connection->query("SELECT * FROM users"); while($row = $statement->fetch(PDO::FETCH_CLASS, "Korisnik")) ( echo $row->getId() . " " . $row->getName(); )

$statement = $connection -> upit ("SELECT * FROM users" ) ;

dok ($red = $naredba -> dohvati (PDO::FETCH_CLASS, "Korisnik") ) (

echo $row -> getId() . " " . $red -> getName () ;

Pripremljeni upiti i vezanje parametara

Da biste razumjeli suštinu i sve prednosti povezivanja parametara, morate detaljnije pogledati mehanizme PDO. Prilikom poziva $statement -> query() u kodu iznad, PDOće pripremiti zahtjev, izvršiti ga i vratiti rezultat.

Prilikom poziva $connection -> pripremi() kreiran je pripremljeni zahtjev. Pripremljeni upiti su sposobnost sistema za upravljanje bazom podataka da primi predložak upita, prevede ga i izvrši nakon preuzimanja vrijednosti varijabli korištenih u predlošku. Predlošci rade na sličan način. Pametno I Grančica.

Prilikom poziva $statement -> execute() vrijednosti za zamjenu se prenose u predložak upita i DBMS izvršava upit. Ova radnja je slična pozivanju funkcije predloška render().

Primjer korištenja pripremljenih upita u PHP PDO:

U gornjem kodu je pripremljen zahtjev za odabir zapisa sa poljem id jednaka vrijednosti koja će biti zamijenjena : id. U ovoj fazi, DBMS će analizirati i kompajlirati zahtjev, po mogućnosti korištenjem keširanja (ovisno o postavkama).

Sada morate proslijediti parametar koji nedostaje i izvršiti zahtjev:

$id = 5; $statement->execute([ ":id" => $id ]);

Prednosti korištenja povezanih parametara

Možda nakon pregleda kako pripremljeni upiti funkcionišu i pridruženih parametara, prednosti njihovog korištenja postaju očigledne.

PDO pruža zgodan način za izbjegavanje korisničkih podataka, na primjer, kod poput ovog više nije potreban:

Umjesto toga, sada je preporučljivo učiniti ovo:

Možete čak i dodatno skratiti kod koristeći numerirane parametre umjesto imenovanih:

U isto vrijeme, korištenje pripremljenih upita poboljšava performanse kada se isti predložak upita više puta koristi. Primjer odabira pet slučajnih korisnika iz baze podataka:

$numberOfUsers = $connection->query("SELECT COUNT(*) FROM users")->fetchColumn(); $users = ; $statement = $connection->prepare("SELECT * FROM users WHERE id = ? LIMIT 1"); za ($i = 1; $i<= 5; $i++) { $id = rand(1, $numberOfUsers); $users = $statement->execute([$id])->fetch(PDO::FETCH_OBJ); )

$numberOfUsers = $connection -> query ("SELECT COUNT(*) FROM users" ) -> fetchColumn () ;

$users = ;

za ($i = 1; $i<= 5 ; $i ++ ) {

$id = rand (1, $numberOfUsers) ;

$users = $naredba -> izvršiti ([ $id ] ) -> dohvatiti (PDO::FETCH_OBJ) ;

Prilikom pozivanja metode pripremiti(), DBMS će analizirati i kompajlirati zahtjev, koristeći keširanje ako je potrebno. Kasnije u ciklusu za, uzorkuju se samo podaci sa navedenim parametrom. Ovaj pristup vam omogućava brže preuzimanje podataka, smanjujući vrijeme rada aplikacije.

Po primitku ukupan broj korisnika u bazi podataka dohvatiColumn(). Ova metoda dohvaća vrijednost jedne kolone i korisna je pri preuzimanju skalarnih vrijednosti kao što su broj, zbir, maksimalne ili minimalne vrijednosti.

Vezane vrijednosti i IN operator

Često, kada počnete da radite sa PDO, javljaju se poteškoće kod operatera IN. Na primjer, zamislite da korisnik unese nekoliko imena odvojenih zarezima. Korisnički unos se pohranjuje u varijablu $name.

U ovom završnom članku ćemo pogledati, šta su pripremljeni upiti, kako uhvatiti greške I šta su transakcije u PDO.

Pripremljeni upiti

Kada pokrenemo upit u bazi podataka, on se analizira i optimizira, za što je, naravno, potrebno vrijeme. Ako imamo puno složenih upita, ovo može potrajati jako dugo da se završi. Koristeći isto pripremljene upite, ovo se radi jednom i onda možemo koristiti naš upit koliko god puta želimo. Također, ne trebamo izbjegavati parametre, jer drajver baze podataka sve će uraditi sam. Pogledajmo kako ih koristiti.

$stmt = $db->prepare("UMETNI U članke (naslov, tekst) VRIJEDNOSTI (:title, :text)");
$stmt->bindParam(":title", $title);
$stmt->bindParam(":text", $text);



$stmt->izvrši();



$stmt->izvrši();

Da bismo pripremili zahtjev, upisujemo ga u metodu pripremiti, gdje umjesto vrijednosti označavamo red ovako: ":ime". U metodi bindParam ukazujemo na koju liniju da priložimo koje podatke. U našem slučaju, do linije :title podaci iz varijable su vezani $title, i do linije :text- podaci iz varijable $text. Da biste izvršili zahtjev, morate pozvati metodu izvršiti. Takvi parametri se nazivaju imenovani, sada pogledajmo neimenovani.

$stmt = $db->prepare("UMETNI U članke (naslov, tekst) VRIJEDNOSTI (?, ?)");
$stmt->bindParam(1, $title);
$stmt->bindParam(2, $text);

$title = "naslov članka 1";!}
$text = "Neki tekst za prvi članak";
$stmt->izvrši();

$title = "naslov članka 2";!}
$text = "Neki tekst za drugi članak";
$stmt->izvrši();

Ovdje je sve identično, osim što umjesto linije :Ime označen je upitnik, a u metodi bindParam broj 1 znači prvo znak pitanja i broj 2 - sekunda upitnik. Koristite metodu koja vam se najviše sviđa.

Hvatanje grešaka

Da bismo uhvatili greške, koristimo konstrukciju koja nam je već poznata probaj-uhvati i klasa PDOException.

Pokušajte (
$db = novi PDO("myql:host=$host;dbname=$dbname", $user, $pass);
) catch(PDOException $e) (
echo "Imate grešku: ".$e->getMessage()."
";
echo "On line: ".$e->getLine();
}

Na primjer, napravio sam grešku i napisao myql, ali ne mysql. Ova greška će biti uhvaćena i biće nam prikazan njen tekst i na kom redu je greška nastala.

Transakcije

hajde da razmotrimo transakcije odmah sa primjerom.

Pokušajte (
$db = novi PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$db->beginTransaction();

$stmt = $db->exec("INSERT INTO `articles`(`title`) VALUES("title1")");
$stmt = $db->exec("INSERT INTO `articles`(`title`) VALUES("title2")");
exit("greška");

$stmt = $db->exec("INSERT INTO `articles`(`title`) VALUES("title3")");
$db->commit();

) catch(PDOException $e) (
$db->rollBack();
}

beginTransaction znači da započinjemo transakciju. Počinite potvrđuje promjene i rollback otkazuje sve.

Suština transakcija je da ili radimo sve ili ne radimo ništa. U našem primjeru umećemo u tabelu članci vrijednosti naslov1, naslov2, naslov3. Ali nakon umetanja druge vrijednosti, simulirali smo grešku zaustavljanjem upotrebe skripte Izlaz. Ako nismo koristili transakcije, onda imamo prva dva naslov bi bio umetnut, ali posljednji ne bi. U našem primjeru to nije značajno, ali postoje slučajevi kada to može dovesti do ozbiljnih kvarova u aplikaciji. Da bismo spriječili da se to dogodi, koristimo se transakcije, gdje metoda rollback vratit će sve u prvobitni oblik i naša prva dva naslov također neće biti umetnuta, a ako je sve prošlo dobro, bez grešaka, onda metoda počinitiće potvrditi promjene i sva tri naslovće biti uspješno umetnuta.

Zaključak

Dakle, u naša tri članka posvećena učenje PDO, pokrili smo sve što vam je potrebno za korištenje ovog sučelja s lakoćom. Mislim da razumete kako PDO olakšava naš život i koristit ćete ga u svojim projektima. Sretno!

Ovo su tabele, ali samo za čitanje (možete napraviti neke promjene, ali su one izuzetno ograničene). U suštini, ovo je obična tabela, ali se kreira na osnovu nekog upita (druge tabele), tj. ovo je 'link' na neki zahtjev. Pogledajmo primjer:

CREATE TABLE t(naziv, cijena); //kreiraj tablicu CREATE VIEW v AS SELECT ime, cijena, ime * cijena AS vrijednost FROM t;//kreiraj drugu tablicu, treće polje kao proizvod prva dva SELECT * FROM v; //preuzimanje podataka iz tabele

One. napravili smo tabelu sa trećim poljem za koje niko ne zna. I ne morate to pokazati svima. One. možemo kreirati tabelu koristeći View, na primjer, u kompaniji, za HR odjel, za zaposlene, za odjel za obuku, za računovodstvo. Radnja je slična korištenju prve tablice kao predloška i dodavanju novih polja u nju.

Pripremljeni upiti

Postoje situacije kada imamo puno zapisa (na primjer, 50000) u bazi podataka, a oni se biraju u petlji. Ako tamo gurnemo mysql_query, onda će ovaj upit biti analiziran 50.000 puta. Da ne bi gubili vrijeme na takvu analizu, postoji pripremljen upit - to je upit koji se unaprijed šalje bazi podataka, analizira se jednom i baza je spremna da ga prihvati. primjer:

Mysql_connect("localhost", "root", "password"); mysql_select_db("test"); mysql_query("PREPARE myinsert FROM // upiši naziv pripremljenog upita "INSERT INTO test_table (ime, cijena) VRIJEDNOSTI (?, ?)""); //ovdje je pripremljeni upit za ($i = 0; $i< 1000; $i++){ mysql_query("SET @name = "Товар # $i""); //установить значение "товар" для переменной @name mysql_query("SET @price = " . ($i * 10)); //установить значение цены для переменной @price mysql_query("EXECUTE myinsert USING @name, @price"); //исполнить подготовленный запрос, используя эти две переменные } mysql_close();

U pripremljenom redu pitanja, umetnute vrijednosti su nepoznate (znak?). Zatim u petlji stavljamo vrijednosti u tabelu. One. unutar mysql jezika vidimo naše varijable, naše funkcije.