Valmisteltu pyyntö

Tietokannan hallintajärjestelmissä valmis kysely tai parametrisoitu kysely on DBMS:n kyky esikääntää tiedoista erotettu SQL-koodi [1] . Valmisteltujen kyselyiden edut:

Valmis lause on itse asiassa esikäännetty malli, joka korvataan vakioarvoilla jokaisen suorituksen aikana, ja on yleistä käyttää SQL DML -käskyjä , kuten INSERT , SELECT tai UPDATE .

Tavallinen järjestys valmisteltujen lausuntojen käyttämiselle on:

INSERT INTO tuotteisiin (nimi, hinta) ARVOT (?, ?);

Vaihtoehto valmiille kyselylle on kutsua SQL suoraan sovelluksen lähdekoodista koodia ja dataa yhdistävällä tavalla. Suora vastaa yllä olevaa esimerkkiä:

INSERT INTO products (nimi, hinta) VALUES ("pyörä", "10900");

Kaikkia optimointeja ei voida suorittaa lausemallin käännöshetkellä kahdesta syystä: paras kyselysuunnitelma voi riippua tietyistä parametriarvoista, ja paras kyselysuunnitelma voi muuttua ajan myötä muuttuvien taulukoiden ja indeksien vuoksi [4] . Kun valmis kysely suoritetaan vain kerran, se toimii hitaammin ylimääräisen edestakaisen matkan vuoksi palvelimelle [5] . Käyttöönoton rajoitukset voivat myös johtaa suorituskyvyn heikkenemiseen; esimerkiksi jotkin MySQL-versiot eivät tallentaneet välimuistiin valmisteltujen kyselyiden tuloksia [6] . Tallennetut menettelyt , jotka myös esikäännetään ja tallennetaan palvelimelle myöhempää suorittamista varten, tarjoavat samanlaisia ​​​​etuja. Toisin kuin tallennettuja proseduureja, valmisteltua kyselyä ei yleensä kirjoiteta proseduurikielellä, eikä se voi käyttää tai muokata muuttujia tai käyttää ohjausvirtarakenteita, vaan se luottaa sen sijaan deklaratiiviseen tietokantakyselykieleen. Yksinkertaisuuden ja asiakaspuolen emulointikyvyn vuoksi (jos kohde-DBMS ei tue niitä), valmistetut kyselyt ovat siirrettävissä paremmin eri DBMS-järjestelmien välillä kuin tallennettuja menettelyjä.

Ohjelmistotuki

Melkein kaikki yleiset tietokantajärjestelmät , mukaan lukien SQLite , [7] MySQL , [8] Oracle , [9] DB2 , [10] Microsoft SQL Server [11] ja PostgreSQL [12] tukevat valmiita kyselyjä. Valmiit kyselyt kutsutaan yleensä käyttämällä erityistä binaariprotokollaa, joka näyttää lisäävän tiedonsiirtonopeutta ja jonka oletetaan edelleen suojaavan SQL-injektiota vastaan, mutta jotkin tietokantajärjestelmät, kuten esimerkiksi MySQL, sallivat virheenkorjaustarkoituksiin kutsua valmiita kyselyitä syntaksin avulla. SQL-kyselyt [13] .

Monet ohjelmointikielet tukevat valmiita kyselyitä vakiokirjastoissaan ja emuloivat niitä tapauksissa, joissa kohdetietokantajärjestelmä ei tue tätä ominaisuutta. Näitä kieliä ovat Java (käyttäen JDBC :tä [14] ), Perl (käyttäen DBI:tä (perl) [15] ), PHP (käyttäen PDO :ta [1] ) ja Python (käyttäen DB-API:tä [16] ) . Asiakaspuolen emulointi voi olla tehokkaampaa yksittäisille pyynnöille ja vähemmän tehokasta useille pyynnöille. Se auttaa myös SQL-injektioita vastaan, samoin kuin valmiiden kyselyjen suora toteuttaminen DBMS-puolella [17] .

Esimerkkejä

Java JDBC

Nämä esimerkit käyttävät Javaa ja JDBC :tä:

tuonti com.mysql.jdbc.jdbc2.optional.MysqlDataSource ; tuonti java.sql.Connection ; tuonti java.sql.DriverManager ; tuonti java.sql.PreparedStatement ; tuonti java.sql.ResultSet ; tuonti java.sql.SQLException ; tuonti java.sql.Statement ; public class Main { public static void main ( String [] args ) heittää SQLExceptionin { MysqlDataSource ds = new MysqlDataSource (); ds . setDatabaseName ( "mysql" ); ds . setUser ( "root" ); try ( Connection conn = ds . getConnection ()) { try ( Lauseke stmt = conn . createStatement ()) { stmt . executeUpdate ( "LUO TAULUKU, JOS EI OLE OLEMASSA tuotteita (nimi VARCHAR(40), hinta INT)" ); } try ( PreparedStatement stmt = conn . readyStatement ( "INSERT INTO Products VALUES (?, ?)" )) { stmt . setString ( 1 , "pyörä" ); stmt . setInt ( 2 , 10900 ); stmt . executeUpdate (); stmt . setString ( 1 , "kengät" ); stmt . setInt ( 2 , 7400 ); stmt . executeUpdate (); stmt . setString ( 1 , "puhelin" ); stmt . setInt ( 2 , 29500 ); stmt . executeUpdate (); } try ( PreparedStatement stmt = conn . readyStatement ( "SELECT * FROM products WHERE name = ?" )) { stmt . setString ( 1 , "kengät" ); ResultSet rs = stmt . executeQuery (); rs . seuraava (); Järjestelmä . ulos . println ( rs . getInt ( 2 )); } } } }

Java PreparedStatementtarjoaa "setterit" ( setInt(int), setString(String), setDouble(double),jne.) kaikille tärkeimmille sisäänrakennetuille tietotyypeille.

PHP SAN

Tässä esimerkissä käytetään PHP :tä ja PDO :ta:

<?php try { // Muodosta yhteys tietokantaan nimeltä "mysql", salasanalla "root" $connection = new PDO ( 'mysql:dbname=mysql' , 'root' ); // Suorita yhteydelle pyyntö, joka luo // taulukon "products" kahdella sarakkeella "nimi" ja "hinta" $connection -> exec ( 'CREATE TABLE IF NOT EXISTS tuotteet (nimi VARCHAR(40), hinta INT)' ); // Valmistele kysely useiden tuotteiden lisäämiseksi taulukkoon $lausunto = $yhteys -> valmistelu ( 'INSERT INTO products VALUES (?, ?)' ); $tuotteet = [ [ 'pyörä' , 10900 ], [ 'kengät' , 7400 ], [ 'puhelin' , 29500 ], ]; // Iteroi tuotteet "products"-taulukossa ja // suorita valmis lause jokaiselle tuotteelle foreach ( $products as $product ) { $lauseke -> suorita ( $tuote ); } // Valmistele uusi lauseke nimetyllä parametrilla $lausunto = $connection -> ready ( 'SELECT * FROM products WHERE nimi = :nimi' ); $lauseke -> suorita ([ ':nimi' => 'kengät' , ]); // Määritä tuotteen nimi ja hinta // vastaaviin muuttujiin [ $product , $price ] = $lausunto -> hae (); // Näytä tulos käyttäjälle echo "Tuotteen hinta { $product } on \$ { $price } ." ; // Sulje kohdistin, jotta `fetch` voidaan lopulta käyttää uudelleen $lauseke -> closeCursor (); } catch ( \Poikkeus $e ) { echo 'Tapahtui virhe:' . $e -> getMessage (); }

Perl DBI

Tämä esimerkki käyttää Perliä ja DBI :tä:

#!/usr/bin/perl -w käytä tiukkaa ; käytä DBI :tä ; my ( $db_name , $db_user , $db_salasana ) = ( 'oma_tietokanta' , 'moi' , 'Passw0rD' ); minun $dbh = DBI -> yhdistä ( "DBI:mysql:tietokanta=$db_nimi" , $db_user , $db_salasana , { RaiseError => 1 , AutoCommit => 1 }) tai die "VIRHE (main:DBI->connect) kun muodostat yhteyden tietokantaan $db_name: " . $ DBI:: errstr . "\n" ; $dbh -> do ( 'LUO TABLE JOS EI OLE tuotteita (nimi VARCHAR(40), hinta INT)' ); my $sth = $dbh -> valmistaa ( 'INSERT INTO products VALUES (?, ?)' ); $sth -> suorita ( @$_ ) foreach [ 'pyörä' , 10900 ], [ 'kengät' , 7400 ], [ 'puhelin' , 29500 ]; $sth = $dbh -> valmistaa ( "SELECT * FROM products WHERE name =?" ); $sth -> suorita ( 'kengät' ); tulosta "$$_[1]\n" foreach $sth -> fetchrow_arrayref ; $sth -> viimeistely ; $dbh -> katkaise yhteys ;

C# ADO.NET

Tämä esimerkki käyttää C# :a ja ADO.NET:iä :

käyttäen ( SqlCommand komento = yhteys . CreateCommand ( ) ) { komento . CommandText = "VALITSE * FROM käyttäjiltä WHERE USERNAME = @käyttäjänimi AND ROOM = @huone" ; komento . Parametrit . AddWithValue ( "@käyttäjänimi" , käyttäjänimi ); komento . Parametrit . AddWithValue ( "@huone" , huone ); käyttäen ( SqlDataReader dataReader = komento . ExecuteReader ()) { // ... } }

Python DB-API

Nämä esimerkit käyttävät Python- ja DB-API:tä:

tuo mysql.connector mysql :n kanssa . liitin . connect ( tietokanta = "mysql" , käyttäjä = "root" ) as conn : with conn . kursori ( valmis = True ) kursorina : kursori . _ execute ( "LUO TABLE JOS EI OLE tuotteita (nimi VARCHAR(40), hinta INT)" ) params = [( "pyörä" , 10900 ), ( "kengät" , 7400 ), ( "puhelin" , 29500 )] kohdistin . executemany ( "INSERT INTO products VALUES ( %s , %s )" , params ) params = ( "kengät" ,) kohdistin . execute ( "SELECT * FROM products WHERE name = %s " , parametrit ) print ( cursor . fetchall ()[ 0 ][ 1 ])

Muistiinpanot

  1. 1 2 PHP Documentation Group Valmistetut lausunnot ja tallennetut menettelyt . PHP käsikirja . Haettu 25. syyskuuta 2011. Arkistoitu alkuperäisestä 8. huhtikuuta 2022.
  2. Shuping Ran, Doug Palmer, Paul Brebner, Shiping Chen, Ian Gorton, Jeffrey Gosper, Lei Hu, Anna Liu ja Phong Tran. J2EE TEKNOLOGIAN SUORITUSKYVYN ARVIOINTIMENETELMÄT . citaseerx.ist.psu.edu . Haettu 15. huhtikuuta 2022. Arkistoitu alkuperäisestä 15. huhtikuuta 2022.
  3. Stephen Thomas, Laurie Williams, Tao Xie. Automaattinen valmisteltu lausekkeiden luominen SQL-injektion haavoittuvuuksien poistamiseksi  //  Tieto- ja ohjelmistotekniikka. - 2009-03-01. — Voi. 51 , iss. 3 . — s. 589–598 . — ISSN 0950-5849 . - doi : 10.1016/j.infsof.2008.08.002 . Arkistoitu alkuperäisestä 9. toukokuuta 2012.
  4. Petrunia, Sergey MySQL Optimizer ja valmistetut lausunnot . Sergei Petrunian blogi (28. huhtikuuta 2007). Haettu 25. syyskuuta 2011. Arkistoitu alkuperäisestä 5. helmikuuta 2018.
  5. Zaitsev, Peter MySQL:n valmistellut lausunnot . MySQL Performance -blogi (2. elokuuta 2006). Haettu 25. syyskuuta 2011. Arkistoitu alkuperäisestä 23. maaliskuuta 2014.
  6. 7.6.3.1. Kuinka kyselyvälimuisti toimii . MySQL 5.1 -käyttöopas . Oraakkeli. Haettu 26. syyskuuta 2011. Arkistoitu alkuperäisestä 25. syyskuuta 2011.
  7. Valmistetut lausumaobjektit . SQLite (18.10.2021). Haettu 9. huhtikuuta 2022. Arkistoitu alkuperäisestä 7. toukokuuta 2022.
  8. Oracle 20.9.4. C API valmistetut lausunnot . MySQL 5.5 -käyttöopas . Haettu 27. maaliskuuta 2012. Arkistoitu alkuperäisestä 30. kesäkuuta 2017.
  9. 13 Oracle Dynamic SQL . Pro*C/C++ esikääntäjän ohjelmointiopas, julkaisu 9.2 . Oraakkeli. Haettu 25. syyskuuta 2011. Arkistoitu alkuperäisestä 26. lokakuuta 2011.
  10. PREPARE- ja EXECUTE-käskyjen käyttö . i5/OS-tietokeskus, versio 5, julkaisu 4 . IBM. Haettu: 25. syyskuuta 2011.  (linkki, jota ei voi käyttää)
  11. SQL Server 2008 R2: SQL-lauseiden valmistelu . MSDN-kirjasto . Microsoft. Haettu 25. syyskuuta 2011. Arkistoitu alkuperäisestä 5. heinäkuuta 2017.
  12. VALMISTELU . PostgreSQL 9.5.1 -dokumentaatio . PostgreSQL Global Development Group. Haettu 27. helmikuuta 2016. Arkistoitu alkuperäisestä 9. maaliskuuta 2018.
  13. Oracle 12.6. SQL-syntaksi valmiille lauseille . MySQL 5.5 -käyttöopas . Haettu 27. maaliskuuta 2012. Arkistoitu alkuperäisestä 16. heinäkuuta 2019.
  14. Valmisteltujen lausuntojen käyttäminen . Java-opetusohjelmat . Oraakkeli. Haettu 25. syyskuuta 2011. Arkistoitu alkuperäisestä 12. marraskuuta 2011.
  15. Bunce, Tim DBI-1.616-spesifikaatio . CPAN . Haettu: 26. syyskuuta 2011.
  16. Python PEP 289: Python Database API Specification v2.0 . Haettu 9. huhtikuuta 2022. Arkistoitu alkuperäisestä 3. maaliskuuta 2022.
  17. Anikin Jevgeni Aleksandrovitš. SQL-injektio ja kuinka suojautua luvattomalta käytöltä  // CONTINUUM. MATEMAA. INFORMATIIKKA. KOULUTUS. - 2016. - Nro 4 . — ISSN 2500-1957 .