Java w Oracle 9i można używać na kilka sposobów :
Java Stored Procedures to zwykle klasy Javy które są przechowywane (w postaci skompilowanej lub razem ze źródłem) w bazie danych. Oracle zapewnia 100% zgodność ze specyfikacją Javy co oznacza, że dowolną klasę Javy można przechowywać i wykonywać na serwerze bazodanowym. Wyjątkami są klasy Javy które korzystają z intefejsu graficznego np. AWT, applety, które nie mogą być wykonywane z oczywistych powodów.
Procedury przechowywane Javy mogą być wykorzystane w trzech kontekstach :
CREATE FUNCTION
- odpowiednik metod Javy, które zwracają wartośćCREATE PROCEDURE
- odpowiednik metod void
JavyINSERT, UPDATE, DELETE, SELECT, CALL , EXPLAIN PLAN, LOCK TABLE oraz MERGE
), w instrukcji CALL
SQL'a, oraz w programach PL/SQL'owych, pakietach itp.
CALL
w ciele triggeraCREATE ... OBJECT
to można zdefiniować metody operujące na tych obiektach jako procedury przechowywane Javy.
Raz skompilowane i przechowywane w takie postaci na serwerze, procedury są szybkie i efektywne. Serwer automatycznie cache'uje kod i rozdziela między wieloma użytkownikami co pozwala odciążyć pamięć i zwiększa szybkość wywołania. Procedury pozwalają realizować logikę biznesową od razu wewnątrz serwera co zwiększa wydajność eliminująć problemy z przepustowością sieci.
Jako rozszerzenie do funkcji SQL, zwiększają moc SQL'a, pozwala uniknąć redundancję w kodzie aplikacji co oszczędza czas i zwiększa produktywność. Procedury przechowywane Javy można tworzyć praktycznie w dowolnym środowisku programistycznym.
Używają automatycznego śledzenia zależności między procedurami pomaga zmniejszyć zapotrzebowanie na pamięć. Mechanizm pamięci współdzielonej w MTS (Multi-Threaded Server) pozwala Oracle'owi obsłużyć do 10,000 równoczesnych użytkowników na jednym węźle.
Raz przetestowane procedury przechowywane mogą być używane w wielu aplikacjach. Wprowadzenie zmian w implementacji bez zmian interfejsu są przezroczyste dla aplikacji. Łatwiej też zarządzać zmianami w procedurach na serwerze niż w wielu rozproszonych aplikacjach. Mechanizm replikacji na serwerze pozwala rozsyłać poprawki w procedurach między wieloma instancjami bazy
Oracle używa mechanizm bezpieczenstwa z Java 2 do ochrony maszyny wirtualnej Javy. Procedury załadowane do bazy danych są traktowane jako nieuwierzytelnione. Dopiero użytkownik z odpowiednimi uprawnieniami moze ich opublikować i dodawać uprawnienia do ich wykonania innym użytkownikom. Dla każdej procedury można ustawić szczegółowe uprawnienia np. pozwalające tylko na UPDATE na tabeli ale bez dostępu do niej (INSERT, SELECT, itp.)
public class Hello { public static String world () { return "Hello world"; } }
loadjava
(lub ręcznie za pomocą polecenia SQL CREATE JAVA
).
Można załadować wcześniej skompilować klasę Javy
loadjava -user scott/tiger Hello.classalbo można polecić
loadjava
skompilowanie w momencie załadowania lub można narzucać kompilowanie dopiero w czasie wywołania tej klasy w bazie.CREATE FUNCTION/CREATE PROCEDURE
create or replace function HELLOWORLD return VARCHAR2 as language java name 'Hello.world () return java.lang.String';
SQL>variable jakisCiag varchar2(100); SQL>call HELLOWORLD INTO :jakisCiag; SQL>print jakisCiag;lub po prostu
SELECT HELLOWORLD FROM DUAL
Wewnętrzy interfejs JDBC uruchomiowy jest wewnątrz aktualnego kontekstu użytkownika w ramach domyślnej transakcji więc nie trzeba już rejestrować driver'ów za pomocą DriverManager
a, zamiast tego można po prostu użyć
Connection conn = DriverManager.getConnection("jdbc:default:connection:");ponieważ procedura jest uruchomiowa wewnątrz bazy driver jest de facto zarejestrowany.
import java.sql.*; import java.io.*; import oracle.jdbc.*; public class RowCounter { public static int rowCount (String tabName) throws SQLException { Connection conn = DriverManager.getConnection("jdbc:default:connection:"); String sql = "SELECT COUNT(*) FROM " + tabName; int rows = 0; try { Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery(sql); while (rset.next()) {rows = rset.getInt(1);} rset.close(); stmt.close(); } catch (SQLException e) {System.err.println(e.getMessage());} return rows; } }
import java.sql.*; import java.io.*; import oracle.jdbc.*; public class DBTrigger { public static void logSal (int empID, float oldSal, float newSal) throws SQLException { Connection conn = DriverManager.getConnection("jdbc:default:connection:"); String sql = "INSERT INTO sal_audit VALUES (?, ?, ?)"; try { PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, empID); pstmt.setFloat(2, oldSal); pstmt.setFloat(3, newSal); pstmt.executeUpdate(); pstmt.close(); } catch (SQLException e) {System.err.println(e.getMessage());} } }Po wczytaniu powyższej klasy Javy do bazy. Zdefiniujemy procedurę
CREATE OR REPLACE PROCEDURE log_sal ( emp_id NUMBER, old_sal NUMBER, new_sal NUMBER) AS LANGUAGE JAVA NAME 'DBTrigger.logSal(int, float, float)';Twórzmy do tego tabele oraz trigger aktualizujący :
CREATE TABLE sal_audit ( empno NUMBER, oldsal NUMBER, newsal NUMBER); CREATE OR REPLACE TRIGGER sal_trig AFTER UPDATE OF sal ON emp FOR EACH ROW WHEN (new.sal > 1.2 * old.sal) CALL log_sal(:new.empno, :old.sal, :new.sal);
row_count
z poprzedniego przykładu :
CREATE PROCEDURE calc_bonus (emp_id NUMBER, bonus OUT NUMBER) AS emp_count NUMBER; ... BEGIN emp_count := row_count('emp'); ... END;
FUNCTION balance (acct_id NUMBER) RETURN NUMBER IS acct_bal NUMBER; BEGIN SELECT bal INTO acct_bal FROM accts WHERE acct_no = acct_id; RETURN acct_bal; END;Możemy tą funkcję wykorzystać w naszym programie w Javie w ten sposób:
CallableStatement cstmt = conn.prepareCall("{? = CALL balance(?)}"); cstmt.registerOutParameter(1, Types.FLOAT); cstmt.setInt(2, acctNo); cstmt.executeUpdate(); float acctBal = cstmt.getFloat(1);
Aby się dostać do bazy danych z poziomu klienta można oczywiście korzystać z interfejsu JDBC. Wyróżnia się dwa sposoby :
TNSNAMES
można użyć :
Connection conn = DriverManager.getConnection ("jdbc:oracle:oci8:@MyHostString", "scott", "tiger");
Connection conn = DriverManager.getConnection ("jdbc:oracle:thin:@mercury:1521:orac", "scott", "tiger");
Oracle 9i w pełni implementuje specyfikację JDBC 2.0 (które były wcześniej dostępne jako rozszerzenia Oracle'a) i obsługuje związane z tym usprawnienia takie jak : Update Batching - zgrupowanie instrukcji INSERT, DELETE, UPDATE
i wysyłanie całą grupą do serwera, Fetch size/row prefetching - zdefiniowanie liczbą wierszy pobranych za jednym razem z kursora/wczytanie z wyprzedzeniem z kursora.
import java.sql.*; import sqlj.runtime.ref.DefaultContext; import oracle.sqlj.runtime.Oracle; #sql iterator MyIter (String ename, int empno, float sal); public class MyExample { public static void main (String args[]) throws SQLException { Oracle.connect ("jdbc:oracle:thin:@mercury:1521:orac", "scott", "tiger"); #sql { insert into emp (ename, empno, sal) values ('SALMAN', 32, 20000) }; MyIter iter; #sql iter={ select ename, empno, sal from emp }; while (iter.next()) { System.out.println (iter.ename()+" "+iter.empno()+" "+iter.sal()); } } }SQLJ pozwala osadzać polecenia SQL wewnątrz kodu Javy. Program w SQLJ jest programem napisanym w Javie zawierające polecenia SQL zgodnie ze specyfikacją ISO-Standard SQLJ Language Reference Syntax. Oracle 9i oferuje obsługę dwóch typów polecen SQL :
Prekompilator napisany w całośći w Javie. Bierz program napisany w SQLJ np. Hello.sqlj generuje plik z rozszrzeniem .java oraz wyciąga polecenia SQL i tworzy dla każdej z nich profil(serializowane zasoby Javy zachowujące informacje o operacjach SQL używanych w kodzie), a potem automatycznie wywołuje kompilator Javy generując pliki .class
Dodatkowo jest jeszcze komponent zwany customizer, który dopasowuje wcześniej wygenerowane profile do konkretnej bazy danych. W przypadku Oracle'a może on wykorzystać specyficzne rozszerzenia i typy dostępne tylko na bazie Oracle.
Programy w SQLJ można wykonywać zarówno z poziomu klienta jak i po stronie serwera.
Z poziomu klienta można wykonywać używając preprocesora sqlj
a potem uruchomić za pomocą polecenia java
Przed wywołaniem procedur SQLJ należy je opublikować w sposób analogiczny jak w przypadku Java Stored Procedures :
sqlj
(można użyć opcji -ser2class
zeby przekształcić wszystkie wynikowe pliki do .class
):
sqlj -ser2class MyExample.sqlj
.class
do jednego archiwum :
jar cvf MyExample.jar MyExample*.class MyIter.class
loadjava -user scott/tiger MyExample.jar
create or replace procedure MYEXAMPLE as language java name 'MyExample.main (java.lang.String[])';
set echo on set serveroutput on set termout on set flush on execute dbms_java.set_output(10000); execute MYEXAMPLE;
SQLJ można używać również wewnątrz Enterprise JavaBeans lub wewnątrz CORBA Server Objects.
22.02.2002