Na tym wykładzie zostaną omówione interfejsy programistyczne określone przez Standard SQL. Dla porównania, przedstawimy tak samo popularny jak ADO interfejs programistyczny do bazy danych – mianowicie JDBC. Należy on do środowiska języka programowania Java i będzie używany na zajęciach dotyczących Javy. Nas interesuje tutaj przede wszystkim porównanie ADO z JDBC - jak bardzo są do siebie podobne, co nie powinno stanowić niespodzianki bo oba wywodzą się z tego samego standardu interfejsu poziomu wywołań (CLI) języka SQL.
Wspomnimy także o łączeniu się z bazami
danych w skryptach języka PHP.
Każdy program zewnętrzny, który chce skorzystać z bazy danych SQL, ma związane ze sobą jeden lub więcej modułów, każdy z nich składa się ze zbioru procedur.
Z kolei każda procedura zawiera zbiór definicji parametrów i pojedynczą instrukcję SQL używającą tych parametrów:
PROCEDURE delete_emp (SQLSTATE, :num_prac NUMBER(4));
DELETE FROM Emp WHERE Emp.Empno = :num_prac;
Parametry poprzedza się dwukropkiem z wyjątkiem standardowych parametrów SQLSTATE i SQLCODE.
Parametr SQLSTATE
Służy do przekazania kodu statusu wykonania instrukcji SQL z powrotem do programu, który wywołuje procedurę.
Wartość SQLSTATE równa 00000 oznacza, że instrukcja SQL została wykonana w całości i nie wystąpił żaden błąd.
Zastosowanie procedury modułowej w C
retcode CHAR(5);
num_prac NUMBER(4);
. . . . . . . . .
CALL delete_emp(RETCODE, num_prac);
IF RETCODE = '00000'
THEN . . . . . . ; /* operacja usuwania powiodła się */
ELSE . . . . . . ; /* wystąpił wyjątek */
Język modułowy umożliwia programom zewnętrznym wykonywanie operacji SQL bez konieczności zmian w składni i semantyce tych języków.
Metodą bardziej naturalną niż tworzenie modułów jest osadzanie instrukcji SQL wprost w tekście programu języka. Tak jak parametry w języku modułowym, nazwy zmiennych języka zewnętrznego w instrukcji osadzonego SQL muszą być poprzedzone dwukropkiem.
EXEC SQL
BEGIN DECLARE SECTION;
SQLSTATE CHAR(5);
num_pr NUMBER(4);
EXEC SQL END DECLARE SECTION;
. . . . . . . . .
EXEC SQL
DELETE FROM Emp WHERE Emp.Empno = :num_pr;
IF SQLSTATE = '00000'
THEN . . . . . . ; /* operacja usuwania powiodła się */
ELSE . . . . . . ; /* wystąpił wyjątek */
EXEC SQL
(więc mogą być łatwo wyróżnione spośród innych instrukcji języka zewnętrznego) i są kończone, na ogół, średnikiem.
Wszystkie zmienne zewnętrzne, które są używane w instrukcjach SQL muszą być zdefiniowane w sekcji deklaracji, ograniczonej instrukcjami
BEGIN DECLARE SECTION
i END DECLARE SECTION.
Po wykonaniu każdej instrukcji SQL do programu na zmiennej SQLCODE lub SQLSTATE (lub obu) jest przekazywana wartość statusu wykonania instrukcji SQL.
Dla języka programowania Java zostały opracowane dwie wersje:
Szczególnie interfejs JDBC stał się popularny i jest używany między innymi w:
JDBC jest zbiorem klas i interfejsów w Javie, które definiują jednolity dostęp do bazy danych z programów napisanych w Javie. Klasy te i interfejsy tworzą pakiet java.sql. Na początku programu zamieszcza się zwykle dyrektywę importu:
import java.sql.*;
Do określenia sposobu łączenia się z bazą danych służy napis połączenia URL (jdbc oznacza nazwę głównego protokołu połączenia):
jdbc:<podprotokół>:<podnazwa>
np.
jdbc:odbc:moja_baza
jdbc:oracle:thin:@xeon.pjwstk.edu.pl:1521:ORCL
Sterownik JDBC - zestaw klas, które implementują interfejsy pakietu java.sql dla konkretnego systemu baz danych. Aby połączyć się z bazą danych należy wykonać dwie instrukcje:
Krok 1: załadowanie odpowiedniego sterownika JDBC do pamięci:
- albo za pomocą mechanizmu Javy dynamicznego ładowania klas:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
- albo używając statycznej metody registerDriver klasy DriverManager:
DriverManager.registerDriver(new sun.jdbc.odbc.JdbcOdbcDriver());
Krok 2: użycie metody getConnection klasy DriverManager do otwarcia połączenia z bazą danych, która zwraca referencję do obiektu klasy Connection.
String URL = "jdbc:odbc:moja_baza"
Connection con = DriverManager.getConnection(URL, "użytkownik",
"hasło");
Oto przykład zastosowania interfejsu JDBC do bazy danych
określonej przez połączenie ODBC o nazwie oras z logowaniem na konto
scott z hasłem tiger. Zakładamy, że w bazie danych znajduje się
tabela Emp mająca kolumny: Ename typu napisowego oraz Sal typu numerycznego.
//połącz się z bazą danych
try { Connection con = |
W przykładzie został użyty sterownik typu
most między JDBC a ODBC. Można byłoby użyć innego
sterownika, na przykład sterownika firmy Oracle. Wtedy przykładowo
URL = "jdbc:oracle:thin:@elektron.pjwstk.edu.pl:1521:ORCL"
. Jako ćwiczenie, czytelnik sprawdzi działanie
załączonego
pełnego programu w Javie - obejmującego powyższy przykład dla bazy danych MS
Access.
Statement stm = con.createStatement();
"UPDATE Emp SET Sal = Sal*1.1"); "Podniesiono zarobki o 10%: "+
liczba +"
osobom."); |
Wywołanie stm.executeUpdate
zwraca pojedynczą liczbę,
określającą liczbę wierszy tabeli, których dotyczyło zapytanie (tzn. które
zostały zaktualizowane). Metoda stm.executeUpdate
używana jest do wykonywania operacji: INSERT, UPDATE, DELETE
, a także operacji definiowania
danych takich jak: CREATE TABLE, ALTER TABLE, DROP TABLE
.
Modyfikowanie danych w bazie danych przy użyciu obiektu ResultSet
Statement stm =
con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE) |
Należy zdawać sobie sprawę, że nie każdy system obsługuje modyfikowalne obiekty ResultSet (podobnie jest dla obiektów RecordSet w ADO).
Usunięcie bieżącego rekordu
rs.deleteRow(); |
Dodanie nowego rekordu
|
Domyślnie w JDBC każda instrukcja SQL kończy się automatycznym zatwierdzeniem (auto-commit). Poniżej zmieniamy to domyślne ustawienie. Gdy wykonywanie wszystkich instrukcji SQL kończy się pomyślnie, explicite wykonujemy zatwierdzanie przy użyciu metody commit obiektu Connection. Gdy w trakcie wykonywania instrukcji SQL powstanie błąd, wykonujemy wycofanie transakcji przy użyciu metody rollback obiektu Connection.
try { |
Obsługa NULL - funkcja
wasNull()
float Sal =
rs.getFloat("Sal"); |
Przygotowanie instrukcji - PreparedStatement
Gdy wielokrotnie wykonuje się tę samą instrukcję, warto ją wcześniej raz przygotować dokonując analizy składniowej, a potem wykonywać wielokrotnie. Co więcej, taka instrukcja może mieć parametry zmieniane przy każdym wywołaniu. W miejsce klasy Statement korzystamy w tym przypadku z jej podklasy PreparedStatement. Parametry formalne są w treści instrukcji oznaczone przez znaki zapytania:
PreparedStatement stmt = con.prepareStatement("UPDATE
Emp SET Deptno = ? WHERE Deptno = ?"); |
Następujące metody służą do nadania wartości parametrom: setInt()
, setString()
,
setDate()
etc. Każda z nich ma dwa argumenty: numer parametru i jego
wartość. Po przygotowaniu
można wielokrotnie nadawać różne wartości temu samemu parametrowi. Oto przykładowy fragment kodu, który przenosi wszystkich pracowników z działu numer 10 do działu nr 50.
PreparedStatement stmt = con.prepareStatement( |
PHP ma bardzo prostą i intuicyjną składnię wzorowaną na C, Javie i Perlu. Popularność zawdzięcza ogromnej liczbie bibliotek, które m.in. pozwalają połączyć się z praktycznie dowolnym systemem zarządzania bazą danych. Co więcej, jest dostępny za darmo i jest oprogramowaniem o otwartym kodzie źródłowym. Stanowi fenomen podobny do Linuxa.
PHP definiuje interfejsy programistyczne dostępu do baz danych - osobno dla każdego konkretnego rodzaju systemu zarządzania bazą danych. W tym punkcie przedstawimy przykład dla bazy danych Oracle.
Skrypty PHP umieszcza się między znacznikami <?php
oraz ?>
lub po prostu <?
oraz ?>
Instrukcje:
echo "treść do wypisania"
print("treść do wypisania")
dopisują tekst do tworzonego dokumentu HTML w celu wyświetlenia go na ekranie
przeglądarki użytkownika.
Nazwy zmiennych poprzedzamy symbolem "$". Jeśli zatem chcemy tę zmienną wypisać na ekran, to piszemy:
<?
$zmienna = "PHP";
echo "Tematem dzisiejszego wykładu jest ". $zmienna;
?>
Połączenie z bazą danych otrzymujemy wywołując funkcję OCILogon. Funkcja OCILogon przekazuje obiekt-połączenie, który pozwala tworzyć obiekty-instrukcje na bazie danych:
$con = OCILogon("scott", "tiger", "myDb");
Gdy połączenie nie jest już potrzebne, należy je zwolnić:
OCILogoff($con);
Aby wykonywać operacje na bazie danych, trzeba utworzyć obiekt-instrukcję. Można go otrzymać na przykład od obiektu-połączenia za pomocą funkcji OCIParse:
$stmt = OCIParse($con, "DELETE FROM Dept WHERE Deptno = 40");
Gdy polecenie jest już gotowe, można je wykonać:
OCIExecute($stmt);
Po wykonaniu polecenia SELECT, można przeglądać jego wyniki za pomocą funkcji
OCIFetchInto. Przesuwa ona kursor o jedną pozycję do przodu i przekazuje true wtedy i tylko wtedy, gdy istnieje kolejny wiersz wyniku. W przeciwnym wypadku wynikiem jest
false.
<?php
$conn = OCILogon("scott", "tiger", "baza");
if ($conn == false){
echo OCIError($conn)."<BR> ";
}
$query = "SELECT Ename, Job, Sal FROM Emp";
$stmt = OCIParse($conn, $query);
if(!$stmt) {// w przypadku błędu przy parsowaniu
$oerr = OCIError($stmt);
echo $oerr["message"];
} else {// gdy nie ma błędu
OCIExecute($stmt);
echo "<TABLE>";
while (OCIFetchInto($stmt, $row, OCI_ASSOC))) {
echo "<TR><TD>$row[ENAME]</TD>"
echo "<TD>$row[JOB]</TD> <TD>$row[SAL]</TD></TR>";
}
echo "</TABLE>";
}
?>
Zwróćmy uwagę na wygodne indeksowanie tabeli zawierającej
wiersz wynikowy $row
za pomocą nazw kolumn np. $row[ENAME]
.
Na dwóch ostatnich wykładach czytelnik zaznajomił się z programistycznym interfejsem poziomu wywołań czyli ze sposobem wykonywania w programie konwencjonalnego języka programowania instrukcji SQL na bazie danych. Porównaliśmy podejścia zastosowane w ADO i JDBC. W obu przypadkach najpierw inicjujemy połączenia z bazą danych za pomocą obiektu klasy Connection. Następnie korzystając z odpowiednich metod albo samego obiektu klasy Connection albo obiektu reprezentującego instrukcję SQL czyli obiektu klasy Command w VBA i Statement w Javie następuje wykonanie instrukcji SQL. W przypadku wykonywania instrukcji SELECT otrzymywane z bazy danych wiersze są zapisywane i przetwarzane przy pomocy metod obiektu RecordSet w VBA i ResultSet w Javie.
W przypadku PHP i bazy danych Oracle używamy funkcji:
OCILogon
do nawiązania połączenia z bazą danych,OCIParse
do przygotowania instrukcji SQL,OCIExecute
do wykonania przygotowanej instrukcji SQL,OCIFetchInto
do sprowadzenia kolejnego wiersza wynikowego -
dla instrukcji SELECT.Strona przygotowana przez Lecha Banachowskiego - 06/12/03 .