SQLJ on SQL - standardin osajoukko, jonka tarkoituksena on yhdistää SQL:n ja Java -syntaksin edut liiketoimintalogiikan toteuttamisen ja tietojen kanssa työskentelyn helpottamiseksi. Tämän standardin on kehittänyt konsortio, joka koostuu IBM :stä , Micro Focusista , Microsoftista , Compaqista (tarkemmin sanottuna sen DBMS-divisioonasta, joka voi johtua pikemminkin ostetun Tandem -yhtiön ansioista ), Informix , Oracle , Sun ja Sybase .
Kun JSQL-konsortio (josta tuli myöhemmin sama nimi sen kehittämän standardin kanssa) ilmestyi vuonna 1997, ajatus relaatiotietokantajärjestelmän ja Java-ohjelmien vuorovaikutuksesta ei ollut uusi. JavaSoft (Sunin tytäryhtiö ) on jo kehittänyt JDBC ( Java DataBase Connectivity ) -rajapinnan , joka sisältyy kielistandardiin JDK 1.1:n julkaisusta lähtien. Tietyistä syistä (katso SQLJ ja JDBC ) tämän käyttöliittymän tarjoamat ominaisuudet eivät kuitenkaan riittäneet.
SQLJ-standardimääritys koostuu kolmesta osasta:
Vuoden 1998 loppuun mennessä spesifikaation kaikki kolme tasoa oli saatu valmiiksi ja toimitettu ANSI :lle harkittavaksi SQL-standardin lisäyksenä. Uuden standardin kaksi ensimmäistä osaa sisällytettiin SQL:1999 - standardin SQL/OLB- ja SQL/PSM -osiin . kolmas osa sisällytettiin erillisenä SQL/JRT - moduulina SQL:2003 -standardiin
Yleensä tietokannan kanssa toimivien sovellusten kehittämisessä SQLJ ymmärretään yleensä tasona 0.
Tässä on yksinkertainen esimerkki Java-luokasta, joka käyttää SQLJ :tä saadakseen kyselytulokset Oraclesta .
tuo java.sql.* ; tuonti oracle.sqlj.runtime.Oracle ; public class SingleRowQuery Extens Base { public static void main ( String [ ] args ) { yritä { yhdistää (); singleRowQuery ( 1 ); } catch ( SQLException e ) { e . printStackTrace (); } } public static void singleRowQuery ( int id ) heittää SQLExceptionin { String fullname = null ; String street = null ; # sql { SELECT fullname , street INTO : OUT fullname , : OUT street FROM customer WHERE ID = : IN id }; Järjestelmä . ulos . println ( "Asiakas, jolla on tunnus = " + id ); Järjestelmä . ulos . println (); Järjestelmä . ulos . println ( koko nimi + " " + katu ); } }Yllä olevasta koodista on selvää, että singleRowQuerySQL-kysely on upotettu itse menettelyn tekstiin, ja tämä upottaminen on järjestetty tiettyjen sääntöjen mukaan:
Kaikkia syntaktisia rakenteita käsitellään yksityiskohtaisesti alla.
On loogista, että herää kysymys syistä luoda kaksi rinnakkaista standardia DBMS-pääsytekniikoiden toteuttamiseksi.
Aluksi on syytä huomata, että SQLJ ja JDBC kuuluvat eri standardiperheisiin ja ovat käsitteellisesti erilaisia. JDBC on Java-kielistandardiin kuuluva API, joka keskittyy ohjelman tuottaman SQL-rakenteen siirtämiseen tietokantaan sekä tuloksen käsittelyyn. SQLJ on SQL SQL / OLB -standardin osajoukko - sille tietokannan käsite on ensisijainen ja kieli, jolla SQL-rakenteet sisällytetään, on toissijainen. Tämän standardin mukaan SQL-lauseiden upottaminen on sallittu paitsi Javassa, myös ohjelmointikielissä Ada , C , COBOL , Fortran , MUMPS , PL/I .
Lisäksi SQLJ:n käyttöön liittyy itse asiassa implisiittisesti JDBC-menetelmien kutsuminen, koska tässä tapauksessa ne toimivat korkean ja matalan tason API :na . Jos perehdyt SQLJ- ja JDBC-tekniikoiden käyttöönoton yksityiskohtiin, voit huomata, että kaikki SQLJ-käskyt muunnetaan ohjelmoijalle läpinäkyvästi JDBC -kutsuiksi erityisellä alijärjestelmällä, jota kutsutaan SQLJ-esiprosessoriksi . Tämän avulla voit turvallisesti sekoittaa SQLJ- ja JDBC-kutsuja samassa koodinpätkässä käyttämällä tarvittaessa yhteistä kontekstia.
Itse asiassa kaikissa erityistapauksissa, joissa SQL-käsky on suoritettava, valinta SQLJ:n ja JDBC:n välillä tulisi tehdä aiotun toiminnon luonteen perusteella. Jos tämä on monimutkainen hakukysely, jossa on mahdollisia vaihteluita hakuehtojen määrässä, olisi ehdottomasti tarkoituksenmukaisempaa muodostaa tekstikyselymerkkijono ja suorittaa se sitten JDBC:n kautta; Jos sinun on vain korvattava joitain muuttujia tai laskettavia lausekkeita, on koodin pituuden kannalta ergonomisempaa kirjoittaa SQLJ-direktiivi.
Jotta SQLJ-standardin tuomia syntaktisia innovaatioita voidaan käyttää tehokkaasti, sinun on ensin ymmärrettävä niiden ominaisuudet, jotka liittyvät SQLJ-konstruktioiden jäsennysprosessiin.
Kaikki SQLJ-rakenteet alkavat direktiivillä #sql, erityisesti SQL-kyselyjä sisältävät lohkot määritellään nimellä #sql {…}.
SQLJ-terminologiassa ulkoinen muuttuja ( eng. host variable ) on SQLJ-konstruktimuuttuja, jota käytetään vastaanottamaan arvoja tai välittämään ne konstruktin ulkopuoliseen ohjelmaympäristöön. Esimerkiksi:
int i , j ; i = 1 ; # sql { VALITSE kenttä INTO : OUT j FROM taulukosta WHERE id = : IN i }; Järjestelmä . ulos . println ( j );Epäselvyyksien välttämiseksi ulkoiset muuttujat on määritettävä tietyssä muodossa, nimittäin:
:[IN|OUT|INOUT] <имя переменной>.
Muuttimet IN, OUT, ovat INOUTvalinnaisia ja niitä käytetään määrittämään muuttujia, vastaavasti, siirtäen arvon ulkopuolelta SQLJ-konstruktioon; palauttaa arvon ulkopuolelle ja suorittaa molemmat toiminnot. Näitä avainsanoja ei käytetä vain tähän - ne asettavat myös pääsytavan ulkoisille muuttujille SQLJ-konstruktion sisällä: jos on modifier IN, vain muuttujan arvon lukeminen on mahdollista, jos läsnä OUT , vain kirjoittaminen, jos läsnä INOUT , täysi pääsy . Oletusarvoisesti (jos eksplisiittisesti määritettyä muuntajaa ei ole) muuttujat ilmoitetaan implisiittisellä modifioijalla INOUT.
SQLJ-konstruktioiden pelkkien muuttujien sijaan voit käyttää ulkoisia muuttujia sisältäviä lausekkeita, joita usein kutsutaan vain ulkoisiksi lausekkeiksi ( englanniksi isäntälausekkeet ). Niillä on erityinen syntaksi:
:( <выражение> )
Pääasiallinen vivahde ulkoisten lausekkeiden käytössä on se, että niiden käytöllä voi olla tiettyjä seurauksia, jotka liittyvät siihen, että esiprosessorin suorittama SQLJ-konstruktin jäsennys useiden ulkoisten lausekkeiden läsnä ollessa etenee tietyssä järjestyksessä, ja kun sitä käytetään määrityslausekkeissa, toimeksiannon tulos voidaan siirtää ohjelmistoympäristöön.
Näiden kahden kohdan havainnollistamiseksi katsotaanpa yksinkertaista esimerkkiä ulkoisten lausekkeiden käytöstä:
int i = 1 ; # sql { VALITSE tulos taulukosta1, MISSÄ kenttä1 = :( x [ i ++] ) JA kenttä2 = :( y [ i ++] ) AND kenttä3 = :( z [ i ++] ) } ; Järjestelmä . ulos . println ( i );Ohjelmointikokemuksen perusteella sitä voidaan yrittää olettaa
Sekä ensimmäinen että toinen väite ovat kuitenkin vääriä. Tämän tarkistamiseksi tehdään yksinkertainen kaavio, joka selventää tämän rakenteen jäsennysjärjestystä SQLJ-esiprosessorilla:
i = 1
x[i++] → x[1], i = 2
y[i++] → y[2], i = 3
z[i++] → z[3], i = 4
Näin ollen:
SQLJ- ja JDBC-terminologiassa yhteyskonteksti on joukko kolmea parametria, jotka ne määrittelevät yksilöllisesti :
Jokaiselle SQLJ-konstruktille konteksti, jossa se suoritetaan, voidaan määrittää erikseen: #sql [<контекст>] {…}.
Direktiivin sisällä #sqlvoit myös luoda uusia konteksteja myöhempää käyttöä varten: #sql context <контекст>. Jos kontekstia ei ole erikseen asetettu, konstruktin katsotaan suoritetuksi oletuskontekstissa . Tarvittaessa oletuskontekstia voidaan muuttaa.
Iteraattori SQLJ-standardin terminologiassa on objekti, joka tallentaa useamman kuin yhden tietueen palauttavan kyselyn tuloksen. Pohjimmiltaan ja toteutuksessaan se ei ole vain tietuejoukko, vaan joukko jossa on jonkin verran järjestystä, joka mahdollistaa vastaanotettujen tietueiden peräkkäisen käytön. Tässä suhteessa iteraattorilla on paljon yhteistä kursorin kanssa .
Standardi tarjoaa kahdenlaisia iteraattoreita - niiden välinen ero on varsin mielenkiintoinen: paikkasidottu iteraattorit vaativat käytössään enemmän SQL:n kaltaista syntaksia, toisin kuin sarakesidottu iteraattorit, jotka ovat käytössä hyvin lähellä objekteja.
Paikointisidotut iteraattoritEnsimmäinen iteraattorityyppi on paikkasidottu iteraattori. Se ilmoitetaan seuraavasti: #sql public iterator ByPos (String, int). On selvää, että tässä tapauksessa kyselytulosten sitominen iteraattoriin suoritetaan yksinkertaisesti sovittamalla tietotyypit iteraattorin ja kyselyn tuloksen välillä. Tämä edellyttää kuitenkin, että iteraattorin ja kyselytuloksen tietotyypit voidaan yhdistää toisiinsa SQL/JRT-standardin mukaisesti.
Luodaan yksinkertainen taulukko:
CREATE TABLE ihmiset ( koko nimi VARCHAR ( 50 ), syntymävuosi NUMEROT ( 4 , 0 ) )Nyt käyttämällä ensimmäisen tyypin iteraattoria ja rakennetta , haemme FETCH … INTO …tiedot kyselyn tuloksesta:
Bypos asennoitin ; Merkkijonon nimi = null ; int vuosi = 0 ; # sql positer = { VALITSE koko nimi , syntymävuosi FROM ihmisiltä }; for (;;) { # sql { FETCH : positer INTO : name , : year }; if ( positer . endFetch ()) break ; Järjestelmä . ulos . println ( nimi + " syntyi vuonna " + vuosi ); }Ensimmäinen direktiivi sitoo kyselyn tuloksen iteraattoriin; toinen, käyttämällä konstruktiota FETCH … INTO …, yksi tietue kerrallaan luetaan tuloksesta peräkkäin.
Iteraattorit sarakkeiden nimilläToinen iteraattorityyppi, joka on lähempänä tavallisia objekteja, on sarakeniminen iteraattori. Määritetylle taulukolle toisen tyypin iteraattorin luominen näyttää tältä:
# sql public iterator ByName ( String fullNAME , int birthYEAR );Sitä käytetään tavallisena objektina, nimittäin pääsy kenttiin tapahtuu vastaavien apuvälinemenetelmien kautta :
ByName nimi ; # sql namiter = { VALITSE koko nimi , syntymävuosi FROM ihmisiltä }; merkkijono s ; int i ; while ( namiter . next ( )) { i = namiteri . syntymäYEAR (); s = nimimerkki . fullNAME (); Järjestelmä . ulos . println ( s + " syntyi " + i ); }On kuitenkin olemassa sääntö, jota on noudatettava - iteraattorikenttien nimien tulee vastata (kirjainkoolla ei väliä) kyselyn kenttien nimien kanssa . Tämä johtuu esiprosessorin suorittamasta SQLJ-rakenteen jäsennysprosessista. Jos tietokannan sarakkeen nimessä on nimi, joka ei ole yhteensopiva Java-muuttujien nimeämissääntöjen kanssa, sinun on käytettävä aliaksia iteraattorin muodostavassa kyselyssä.
Proseduurikutsut on erittäin helppo kirjoittaa ulkoisten muuttujien avulla.
# sql { CALL proc (: myarg )};Funktioita puolestaan kutsutaan konstruktia käyttämälläVALUE
int i ; # sql i = { ARVOT ( func ( 34 ))};Koska SQLJ-direktiivit käyttävät JDBC-kutsuja, kun niitä käytetään, on mielenkiintoista pystyä käyttämään näitä tekniikoita yhdessä. Iteraattorit on tarpeeksi helppoa muuntaa objekteiksi ResultSetja päinvastoin.
Objektin muuntaminen ResultSeton erittäin helppoa. Tätä varten sinun on ensin määritettävä iteraattori sarakkeiden nimillä (esimerkissämme se merkitään Employees), ja suorita sitten toiminto CAST:
# sql iterator Työntekijät ( String ename , double sal ); PreparedStatement stmt = conn . valmisteleLaumaus (); String query = "SELECT ename, sal FROM emp WHERE" ; kysely += whereClause ; ResultSet rs = stmt . executeQuery ( kysely ); Työntekijät emps ; # sql emps = { CAST : rs }; while ( emps . next ( )) { System . ulos . println ( emps . ename () + " ansaitsee " + emps . sal ()); } emps . sulje (); stmt . sulje ();Erikseen tulee huomioida, että kun kyselytulos on sidottu iteraattoriin, kyselyn tulosta ei tarvitse erikseen sulkea - esiprosessori itse tekee sen ohjelmoijan puolesta.
Käänteinen prosessi - iteraattorin muuntaminen objektiksi ResultSetsuoritetaan käyttämällä erityistyyppisiä iteraattoreita, niin sanottuja heikosti tyypitettyjä iteraattoreita .
sqlj . ajoaika . ResultSetIterator iter ; # sql iter = { VALITSE ename FROM emp }; ResultSet rs = iter . getResultSet (); while ( rs . next ( )) { System . ulos . println ( "työntekijän nimi: " + rs . getString ( 1 )); } iter . sulje ();Tässä tapauksessa myös iteraattorin ja kyselyn tuloksen välinen suhde säilyy ja iteraattori tulee sulkea.
Kuten aiemmin mainittiin, helpoin tapa verrata SQLJ:tä teknologiana on samankaltainen Java-suuntautunut tekniikka samaan tarkoitukseen, nimittäin JDBC. Tilannetta mutkistaa se, että nämä tekniikat eivät ole rinnakkaisia eivätkä täysin vaihdettavissa keskenään, vaan ovat arkkitehtonisesti päällekkäisiä.
http://www-01.ibm.com/software/data/informix/pubs/library/iif.html
katso Embedded SQLJ User's Guide