SQLJ

SQLJ  je podmnožinou standardu SQL zaměřeného na kombinaci výhod syntaxe SQL a Java pro pohodlí implementace obchodní logiky a práce s daty. Tento standard vyvinulo konsorcium složené z IBM , Micro Focus , Microsoft , Compaq (přesněji jeho divize DBMS, kterou lze spíše připsat na vrub převzaté společnosti Tandem ), Informix , Oracle , Sun a Sybase .

Pozadí

V době, kdy se v roce 1997 objevilo konsorcium JSQL (které se později stalo stejným názvem se standardem, který vyvinulo) , nebyla myšlenka interakce mezi relačními DBMS a Java programy nová. JavaSoft ( dceřiná společnost Sunu) již vyvinul rozhraní JDBC ( Java DataBase Connectivity )  , které je  součástí jazykového standardu od vydání JDK 1.1. Z určitých důvodů (viz SQLJ a JDBC ) však funkce poskytované tímto rozhraním nestačily.

Standardní specifikace SQLJ se skládá ze tří částí:

Do konce roku 1998 byly všechny tři úrovně specifikace dokončeny a předloženy ANSI k posouzení jako dodatky ke standardu SQL. První dvě části nového standardu byly zahrnuty do částí SQL/OLB a SQL/PSM standardu SQL:1999 ; třetí část byla zařazena jako samostatný modul SQL/JRT ve standardu SQL:2003

Obvykle se ve vztahu k vývoji aplikací, které pracují s databází, SQLJ obvykle chápe jako úroveň 0.

Ukázkový kód

Zde je jednoduchý příklad třídy Java, která používá SQLJ k získání výsledků dotazů z Oracle .

import java.sql.* ; import oracle.sqlj.runtime.Oracle ; public class SingleRowQuery extends Base { public static void main ( String [] args ) { try { connect (); singleRowQuery ( 1 ); } catch ( SQLException e ) { e . printStackTrace (); } } public static void singleRowQuery ( int id ) vyvolá výjimku SQL { String fullname = null ; String street = null ; # sql { SELECT celé jméno , ulice INTO : OUT celé jméno , : OUT ulice FROM zákazníka WHERE ID = : IN id }; Systém . ven . println ( "Zákazník s ID = " + id ); Systém . ven . println (); Systém . ven . println ( celé jméno + " " + ulice ); } }

Z výše uvedeného kódu je zřejmé, že singleRowQuerySQL dotaz je vložen do textu samotné procedury a toto vložení je organizováno podle určitých pravidel:

  • Text požadavku je uvnitř směrnice #sql {...};
  • Proměnné mimo SQL dotaz jsou v něm nastaveny ve specifickém formátu

Všechny syntaktické konstrukce budou podrobně diskutovány níže.

SQLJ a JDBC

Je logické, že vyvstává otázka důvodů pro vytvoření dvou paralelních standardů pro implementaci přístupových technologií DBMS.

Pro začátek stojí za zmínku, že SQLJ a JDBC patří do různých rodin standardů a jsou koncepčně odlišné. JDBC je API, které je součástí jazykového standardu Java a je zaměřeno na přenos SQL konstruktu generovaného programem do databáze a také na zpracování výsledku. SQLJ je podmnožinou standardu SQL SQL / OLB  – koncept databáze je pro něj primární a jazyk, ve kterém jsou konstrukty SQL zahrnuty, je sekundární. Podle tohoto standardu je vkládání SQL příkazů povoleno nejen v Javě, ale také v programovacích jazycích Ada , C , COBOL , Fortran , MUMPS , PL/I .

Dále použití SQLJ ve skutečnosti implicitně zahrnuje volání metod JDBC, protože v tomto případě fungují jako vysokoúrovňové a nízkoúrovňové API . Pokud se ponoříte do podrobností implementace technologií SQLJ a JDBC, zjistíte, že všechny direktivy SQLJ jsou pro programátora překládány do volání JDBC transparentně pomocí speciálního subsystému zvaného SQLJ preprocessor . To vám umožní bezpečně kombinovat volání SQLJ a JDBC ve stejném fragmentu kódu, v případě potřeby pomocí společného kontextu.

Ve skutečnosti by v každém konkrétním případě, kdy je třeba provést příkaz SQL, měla být volba mezi SQLJ a JDBC provedena na základě povahy zamýšlené operace. Pokud se jedná o složitý vyhledávací dotaz s možnými variacemi v počtu vyhledávacích podmínek, pak by rozhodně bylo účelnější vytvořit textový řetězec dotazu a ten pak provést prostřednictvím JDBC; pokud potřebujete pouze nahradit nějaké proměnné nebo vyčíslitelné výrazy, pak bude z hlediska délky kódu ergonomičtější napsat direktivu SQLJ.

Syntaxe

Abyste mohli efektivně využívat syntaktické inovace zavedené standardem SQLJ, musíte nejprve porozumět jejich funkcím souvisejícím s procesem analýzy konstrukcí SQLJ.

Jakékoli konstrukce SQLJ začínají direktivou #sql, konkrétně bloky obsahující samotné dotazy SQL jsou specifikovány jako #sql {…}.

Externí proměnné

V terminologii SQLJ je externí proměnná ( anglicky  host variable ) konstruktová proměnná SQLJ používaná k přijímání hodnot nebo k jejich předávání do programového prostředí mimo konstrukci. Například:

int i , j ; i = 1 ; # sql { SELECT pole INTO : OUT j FROM tabulka WHERE id = : IN i }; Systém . ven . println ( j );

Aby se předešlo nejasnostem, musí být externí proměnné specifikovány v určité formě, konkrétně:

:[IN|OUT|INOUT] <имя переменной>.

Modifikátory IN, OUTjsou INOUTvolitelné a používají se ke specifikaci proměnných, respektive předávání hodnoty zvenčí do konstrukce SQLJ; vrácení hodnoty ven a provedení obou funkcí. Tato klíčová slova se používají nejen k tomu - nastavují také přístupovou metodu k externím proměnným uvnitř konstrukce SQLJ: pokud existuje modifikátor IN, je možné pouze čtení hodnoty proměnné, pokud je přítomna OUT , pouze zápis, pokud je přítomna INOUT , plný přístup . Ve výchozím nastavení (při absenci explicitně specifikovaného modifikátoru) jsou proměnné deklarovány s implicitním modifikátorem INOUT.

Vnější výrazy

Místo pouhých proměnných v konstrukcích SQLJ můžete použít výrazy obsahující externí proměnné, často nazývané pouze externí výrazy ( anglicky  host expressions ). Mají specifickou syntaxi:

:( <выражение> )

Hlavní nuance při použití externích výrazů spočívá v tom, že jejich použití může mít za následek určité důsledky související se skutečností, že analýza konstruktu SQLJ preprocesorem v přítomnosti několika externích výrazů probíhá v určitém pořadí a při použití v přiřazovacích výrazech výsledek zadání lze přenést do softwarového prostředí.

Pro ilustraci těchto dvou bodů se podívejme na jednoduchý příklad použití externích výrazů:

int i = 1 ; # sql { SELECT result FROM table1 WHERE field1 = :( x [ i ++] ) AND field2 = :( y [ i ++] ) AND field3 = :( z [ i ++] ) }; Systém . ven . println ( i );

Na základě zkušeností s programováním to lze zkusit předpokládat

  1. Hodnota proměnné ise během analýzy příkazu SQL nezmění;
  2. Vygenerovaný dotaz bude vypadat takto
VYBERTE výsledek Z tabulky1 WHERE pole1 = :( x [ 1 ]) AND pole2 = :( y [ 1 ]) AND pole3 = :( z [ 1 ])

První i druhé tvrzení jsou však nepravdivé. Chcete-li to zkontrolovat, vytvořte jednoduchý diagram, který objasňuje pořadí analýzy tohoto konstruktu preprocesorem SQLJ:

i = 1
x[i++] → x[1], i = 2
y[i++] → y[2], i = 3
z[i++] → z[3], i = 4

Tudíž:

  1. Po provedení direktivy SQLJ se objeví i = 4;
  2. Požadavek bude proveden
VYBERTE výsledek Z tabulky1 WHERE pole1 = :( x [ 1 ]) AND pole2 = :( y [ 2 ]) AND pole3 = :( z [ 3 ])

Souvislosti

V terminologii SQLJ a JDBC je kontext připojení sada tří parametrů, které jsou jimi jednoznačně definovány:

  1. jméno databáze;
  2. identifikátor relace;
  3. ID aktivní transakce.

Pro jakoukoli konstrukci SQLJ lze explicitně definovat kontext, ve kterém bude provedena: #sql [<контекст>] {…}.

V rámci směrnice #sqlmůžete také vytvořit nové kontexty pro pozdější použití: #sql context <контекст>. Pokud kontext není explicitně nastaven, pak se konstrukce považuje za spuštěnou ve výchozím kontextu .  V případě potřeby lze výchozí kontext změnit.

Iterátory

Iterátor v terminologii standardu SQLJ je objekt pro uložení výsledku dotazu, který vrací více než jeden záznam. Ve své podstatě a provedení se nejedná pouze o soubor záznamů, ale o soubor s určitým uspořádáním, který umožňuje používat přijaté záznamy sekvenčně. V tomto ohledu má iterátor mnoho společného s kurzorem .

Standard poskytuje dva typy iterátorů – rozdíl mezi nimi je docela zajímavý: iterátory vázané na pozici vyžadují při použití syntaxi více podobnou SQL, na rozdíl od iterátorů vázaných na sloupce, které jsou velmi blízké objektům.

Iterátory vázané na pozici

Prvním typem iterátoru je iterátor vázaný na pozici. Deklaruje se takto: #sql public iterator ByPos (String, int). Je jasné, že v tomto případě se vazba výsledků dotazu na iterátor provádí jednoduše porovnáním datových typů mezi iterátorem a výsledkem dotazu. To však vyžaduje, aby datové typy iterátoru a výsledku dotazu mohly být navzájem mapovány podle standardu SQL/JRT.

Vytvoříme jednoduchou tabulku:

CREATE TABLE lidé ( celé jméno VARCHAR ( 50 ), rok narození NUMERIC ( 4 , 0 ))

Nyní pomocí iterátoru prvního typu a konstrukce FETCH … INTO …načteme data z výsledku dotazu:

Bypos polohovadlo ; Název řetězce = null ; int rok = 0 ; # sql positer = { SELECT celé jméno , rok narození FROM lidí }; for (;;) { # sql { FETCH : positer INTO : name , : year }; if ( positer . endFetch ()) break ; Systém . ven . println ( jméno + " se narodil v " + rok ); }

První direktiva váže výsledek dotazu k iterátoru; druhý, pomocí konstrukce FETCH … INTO …, jeden záznam po druhém je postupně čten z výsledku.

Iterátory s názvy sloupců

Druhým typem iterátoru, který se používá blíže k běžným objektům, je iterátor s názvem sloupec. Pro zadanou tabulku bude vytvoření iterátoru druhého typu vypadat takto:

# sql public iterator ByName ( String fullNAME , int bornYEAR );

Používá se jako běžný objekt, jmenovitě přístup k polím se provádí pomocí odpovídajících metod přístupového objektu:

ByName jméno ; # sql namiter = { SELECT celé jméno , rok narození FROM lidí }; Řetězec s ; int i ; while ( namiter . next ()) { i = namiter . narozeníYEAR (); s = namiter . fullNAME (); Systém . ven . println ( s + " se narodil v " + i ); }

Existuje však pravidlo, které je třeba dodržet - názvy polí iterátoru se musí shodovat (nerozlišují se malá a velká písmena) s názvy polí v dotazu . To je způsobeno procesem analýzy konstrukce SQLJ preprocesorem. Pokud má název sloupce v databázi název, který není kompatibilní s pravidly pro pojmenování proměnných v jazyce Java, musíte v dotazu, který tvoří iterátor, použít aliasy.

Volání procedur a funkcí

Volání procedur se velmi snadno zapisují pomocí externích proměnných.

# sql { CALL proc (: myarg )};

Funkce se zase volají pomocí konstruktuVALUE

int i ; # sql i = { HODNOTY ( func ( 34 ))};

Interakce s JDBC

Vzhledem k tomu, že direktivy SQLJ používají volání JDBC, když jsou používány, je zajímavé mít možnost používat tyto technologie společně. Je dost snadné převést iterátory na objekty ResultSeta naopak.

Transformace objektu ResultSetje velmi snadná. Chcete-li to provést, musíte nejprve definovat iterátor s názvy sloupců (v našem příkladu bude označen Employees) a poté provést operaci CAST:

# sql iterator Zaměstnanci ( String ename , double sal ); PreparedStatement stmt = conn . připravitProhlášení (); String query = "SELECT ename, sal FROM emp WHERE" ; dotaz += whereClause ; ResultSet rs = stmt . executeQuery ( dotaz ); Zaměstnanci emps ; # sql emps = { CAST : rs }; while ( emps . next ()) { System . ven . println ( emps . ename () + "vydělává" + emps . sal ()); } emps . zavřít (); stmt . zavřít ();

Samostatně je třeba poznamenat, že po navázání výsledku dotazu na iterátor není potřeba samostatně zavírat výsledek dotazu - to udělá za programátora samotný preprocesor.

Zpětný proces - převod iterátoru na objekt ResultSetse provádí pomocí iterátorů speciálního typu, tzv. slabě typovaných iterátorů . 

sqlj . runtime . ResultSetIterator iter ; # sql iter = { SELECT ename FROM emp }; ResultSet rs = iter . getResultSet (); while ( rs . next ()) { System . ven . println ( "jméno zaměstnance: " + rs . getString ( 1 )); } iter . zavřít ();

V tomto případě je také zachován vztah mezi iterátorem a výsledkem dotazu a je to iterátor, který by měl být uzavřen.

Vlastnosti SQLJ

Jak již bylo zmíněno dříve, nejjednodušší způsob, jak porovnat SQLJ jako technologii, je s podobnou technologií orientovanou na Java pro stejný účel, konkrétně JDBC. Situaci komplikuje skutečnost, že tyto technologie nejsou paralelní a nejsou zcela zaměnitelné, ale jsou architektonicky nad sebou.

  1. Dotaz stejného účelu, napsaný ve voláních JDBC a v direktivě SQLJ, bude ve většině případů zapsán kompaktněji v textu programu ve druhém případě, což snižuje velikost výpisu a pravděpodobnost chyby spojené se sestavováním. konečný řetězec dotazu z malých fragmentů;
  2. Jakákoli direktiva SQLJ je analyzována a kontrolována preprocesorem ve fázi kompilace, proto jsou v této fázi detekovány všechny syntaktické chyby, na rozdíl od JDBC, kde je správnost konstrukcí kontrolována pouze z hlediska syntaxe Java - již je zodpovědný DBMS pro analýzu a opravu samotného dotazu, což přirozeně vede k tomu, že chyby tohoto druhu budou detekovány již ve fázi spuštění;
  3. Samotný preprocesor (obvykle pojmenovaný sqlj) není součástí JDK ; jej a knihovny potřebné pro jeho provoz obvykle poskytuje prodejce DBMS. To je přirozené – jak je ukázáno výše, SQLJ má mnohem blíže k DBMS než k samotnému jazyku Java; navíc preprocesor musí brát v úvahu zvláštnosti syntaxe SQL „svého“ DBMS;
  4. Ve většině případů, zejména u často prováděných složitých dotazů, které pracují s velkým množstvím dat, se direktiva SQLJ provede v průměru rychleji než podobná sada volání JDBC. To je způsobeno tím, že plán pro odpovídající dotaz v případě direktivy SQLJ bude sestaven pouze jednou a poté znovu použit, na rozdíl od JDBC, kde bude plán sestaven na každém volání;
  5. Plán dotazů vytvořený během překladu direktivy SQLJ může být v případě potřeby konfigurován uživatelem; v případě JDBC to z pochopitelných důvodů není možné;
  6. Pokud dotaz vyžaduje v každém případě významné změny (jednoduchý příklad: vyhledávací dotaz na sadu polí, z nichž některá mohou mít chybějící hodnoty), je jednodušší použít JDBC, protože použití SQLJ nemá žádné výhody;
  7. Protože při použití JDBC není potřeba další fáze zpracování kódu - překlad, bude proces kompilace v tomto případě rychlejší.

Nevýhody SQLJ

  1. SQLJ vyžaduje další krok předběžného zpracování.
  2. Většina IDE nemá podporu SQLJ.
  3. SQLJ nemá podporu ve většině rámců ORM, jako je Hibernate.

Softwarová podpora

Oracle

DB/2

Informix

http://www-01.ibm.com/software/data/informix/pubs/library/iif.html

viz Uživatelská příručka vestavěného SQLJ

Odkazy

  1. Andrew Eisenberg, Jim Melton. Vazby pro objektové jazyky ​​(mrtvý odkaz) . Získáno 12. listopadu 2008. Archivováno z originálu 17. září 2011. 
  2. Andrew Eisenberg, Jim Melton. SQLJ - Část 1 (nedostupný odkaz) . Získáno 12. listopadu 2008. Archivováno z originálu 13. února 2009. 
  3. IBM Redbooks. DB2 for z/OS a OS/390: Připraveno pro Java (odkaz není k dispozici) . Získáno 12. listopadu 2008. Archivováno z originálu 25. srpna 2011. 
  4. Oracle Database 11g. SQLJ Developer's Guide and Reference (nedostupný odkaz) . Získáno 12. listopadu 2008. Archivováno z originálu 25. srpna 2011.