Zielony Smok - logo witryny

Apache Derby: zrozumienie systemu

Tryb wbudowany

Używa sterownika EmbeddedDriver.

Na ogół mamy trzy elementy składowe:

  • Aplikacja łącząca się z bazą danych
  • Derby
    • sterownik JDBC EmbeddedDriver
    • silnik Derby
  • Baza danych

Wszystkie powyższe elementy działają w obrębie jednej JVM.

Aplikacja ładuje sterownik EmbeddedDriver. W JDK 5.0 sterownik musi być załadowany (zarejestrowany) przy użyciu odpowiedniego polecenia. W JDK 6.0 i późniejszych sterownik jest ładowany (rejestrowany) automatycznie w momencie połączenia. Zwyczajowo przyjmuje się jednak, że i tak wykonujemy polecenie ładujące, chociaż nie jest to zalecane. Istnieją bowiem sytuacje, w których sterownik może zostać wyrejestrowany i istnieje konieczność jego ponownego załadowania.

Sterownik można załadować używając następującej metody:

private static boolean loadDBDriver(String driverName)
            throws IllegalArgumentException {
        if (driverName.equals("EmbeddedDriver")
                || driverName.equals("ClientDriver")) {
            try {
                try {
                    Class.forName("org.apache.derby.jdbc." + driverName).getDeclaredConstructors()[0].newInstance();
                } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                return false;
            }
        } else {
            throw new IllegalArgumentException("Niewłaściwa nazwa sterownika");
        }
        return true;
    }

Załadowanie sterownika powoduje uruchomienie silnika Derby. W danej JVM może być uruchomiony tylko jeden silnik Derby na raz. Wyrejestrowanie sterownika następuje wraz z zatrzymaniem silnika, ale wyrejestrowanie sterownika nie zatrzymuje silnika Derby. W czasie działania aplikacji można wyrejestrować sterownik używając polecenia

DriverManager.deregisterDriver(org.apache.derby.jdbc.EmbeddedDriver) i zarejestrować ponownie używając polecenia

Class.forName("org.apache.derby.jdbc." + driverName).getDeclaredConstructors()[0].newInstance();. W momencie, gdy sterownik jest wyrejestrowany – nie mamy możliwości połączenia z bazą danych.

Silnik można uruchomić używając następującej metody:

public static boolean startDerbyEngine(String driverName) {
        return loadDBDriver(driverName);
    }

Uruchomienie silnika powoduje powstanie ‘systemu Derby’ Silnik odczytuje położenie folderu systemowego Derby z
pliku derby.properties. Jeśli folder nie został wskazany, folderem systemowym będzie
folder domyślny czyli folder, w którym umieszczona jest aplikacja. W tym folderze systemowym będzie zapisywany
plik derby.log oraz będzie utworzona baza danych – jedna lub więcej. Właściwości
umieszczone w pliku derby.properties są właściwościami systemu i obowiązują dla
wszystkich baz danych.

Folder systemowy można wskazać przy użyciu poniższej metody:

 public static void setDBSystemDir(String dirName) {
        String userHomeDir = System.getProperty("user.home", ".");
        String systemDir = userHomeDir + "/." + dirName;
        System.setProperty("derby.system.home", systemDir);
    }

Aplikacja uruchamia połączenie do bazy danych. Baza danych startuje. Połączenie jest nawiązane.

Jeśli bazy nie było, a w atrybutach połączenia podaliśmy create=true baza danych zostaje utworzona, w folderze systemu Derby. Baza startuje, połączenie zostaje nawiązane. Od tej chwili baza danych jest osadzona w aplikacji, a silnik Derby zapewnia aplikacji wyłączność na obsługę tej bazy. Żadna inna aplikacja w czasie ‘osadzenia’ nie może połączyć się z tą bazą danych. Silnik Derby blokuje taką możliwość.

Aby użyć atrybutów połączenia możemy użyć następujących metod:

 public static Connection connectEmbeddedDB(String dbName, String properties) {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection("jdbc:derby:" + dbName + ";" + properties);
        } catch (Throwable e1) {
            e1.printStackTrace();
        }
        return conn;
    }
 public static Connection connectEmbeddedDB(String dbName, Properties props) {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection("jdbc:derby:" + dbName, props);
        } catch (Throwable e1) {
            e1.printStackTrace();
        }
        return conn;
    }

Baza danych zawsze istnieje w obrębie systemu Derby. Jeśli baza, z którą łączy się aplikacja występuje poza systemem Derby, w momencie połączenia, automatycznie staje się częścią tego systemu. Każda baza jest podfolderem folderu systemu Derby. Nazwa podfolderu jest nazwą bazy danych.

Jeżeli uruchomimy więcej niż jedną instancję aplikacji, każda z tych aplikacji ma własną kopię bazy danych i programu Derby.

W obrębie systemu Derby może istnieć więcej niż jedna baza danych.

Aplikacja może nawiązywać więcej połączeń z daną bazą danych. Aplikacja może łączyć się z różnymi bazami danych w obrębie tego samego systemu.

Aplikacja zamyka połączenie z bazą danych. Silnik Derby zwalnia zasoby przyznane dla połączenia. Inne połączenia nadal są aktywne. Baza danych nadal działa. Nawet wtedy, gdy zostało zamknięte ostatnie połączenie do tej bazy.

Aby zamknąć połączenie z baza danych możemy uzyc metody close(Connection) z klasy
DerbyUtil.

Aplikacja zamyka bazę danych. Baza danych zostaje zatrzymana. Wszystkie połączenia do tej bazy są automatycznie rozłączane, ale istnieją nadal jako obiekty. Jeśli spróbujesz użyć takiego połączenia – zostanie wyrzucony wyjątek. Dlatego dokumentacja zaleca zamykanie wszystkich połączeń przed zamknięciem bazy albo systemu. Baza danych przestaje być osadzona w aplikacji i może przyjmować połączenia od innych aplikacji (może być osadzona w innej aplikacji). Pozostałe bazy nadal działają. Silnik Derby nadal działa.

Aby zamknąć aplikację możemy użyć metody shutdownEmbeddedDB(String dbName) z klasy
DerbyUtil zawierającej polecenie zamknięcia bazy:

DriverManager.getConnection("jdbc:derby:" + dbName + ";shutdown=true");

Aplikacja zatrzymuje silnik Derby. Wszystkie bazy danych (i wszystkie połączenia do tych baz danych) zostają rozłączone.

Aby zatrzymać silnik Derby można użyć metody shutdownDerbyEngine() z klasy DerbyUtil, zawierającej polecenie zatrzymania silnika:

DriverManager.getConnection("jdbc:derby:;shutdown=true");

Zamknięcie aplikacji tworzącej połączenie nie zatrzymuje silnika Derby.

Tryb klient/serwer

Używa sterownika ClientDriver.

Na ogół mamy cztery elementy:

  • Aplikacja kliencka łącząca się z bazą danych przez sieć
  • Aplikacja zarządzająca połączeniami (serwer)
  • Derby (system Derby)
    • silnik Derby
  • Baza danych – jedna lub więcej

Aplikacja kliencka na ogół działa na innym komputerze niż pozostałe trzy elementy układu chociaż może działać na tym samym komputerze. Aplikacja kliencka nie uruchamia silnika Derby i nie powoduje powstania systemu Derby. Aplikacja kliencka musi podać adres (lokalny lub zdalny) serwera bazy danych. Ze względów bezpieczeństwa, ustawienia domyślne serwera pozwalają na przyjmowanie wyłącznie połączeń lokalnych. Aby serwer przyjmował połączenia zdalne (z innych komputerów) należy zmienić ustawienia konfiguracyjne serwera.

Połączenie zostanie ustanowione jeśli na komputerze zdalnym:

  • serwer sieciowy jest uruchomiony i dostępny w sieci
  • serwer sieciowy zezwala na połączenie z naszego adresu IP. Dopóki nie zostaną wyspecyfikowane prawa dostępu baza sieciowa jest dostępna wyłącznie z komputera z zainstalowanym serwerem
  • baza danych o podanej przez nas nazwie istnieje na serwerze

Połączenie ze zdalną bazą danych można uruchomić przy użyciu metody connectServerDB z klasy DerbyUtil.

Serwer jest w zasadzie aplikacją, która została opisana w punkcie omawiającym system wbudowany. Serwer może przyjmować wiele połączeń do bazy danych z różnych aplikacji klienckich w tym samym czasie. Zadaniem serwera jest przyjmowanie połączeń do bazy i obsługa tych połączeń, tak aby zapewnić maksymalną efektywność działania bazy danych.

Aby wystartować server możemy uzyć metody startDerbyNetworkServer z klasy DerbyUtil.

Aplikacja kliencka zamyka połączenie. Serwer działa nadal. Baza danych na serwerze działa nadal.

Baza danych na serwerze jest zatrzymana. Wszystkie połączenia do tej bazy zostają automatycznie zamknięte. Baza przestaje być wbudowana w serwer. Jest osiągalna dla aplikacji działających na serwerze w trybie embedded i może być osadzona w którejś z nich. Serwer działa nadal.

Serwer jest zatrzymany. Baza danych budowana w serwer zostaje zatrzymana.

Klasa derbyUtil zawiera metody pozwalające na zamknięcie bazy danych na serwerze oraz na zatrzymanie serwera.

Jeśli zabraknie przestrzeni dyskowej i baza danych nie może alokować więcej przestrzeni dyskowej na swoje potrzeby- system Derby ulega zamknięciu.

Inne serwery baz danych

Zamiast używania serwera dostarczanego wraz z Derby można użyć innego gotowego serwera lub napisać własny. Takie serwery jak WebSphere Application Server czy Apache Tomcat – zapewniają dodatkowe możliwości np. usługi sieciowe (web service), czy tworzenie puli połączeń. Będziemy o tym mówili w dalszych wpisach.

Rejestracja błędów

Po uruchomieniu systemu wszystkie informacje wyjściowe oraz informacje o błędach są zapisywane w pliku derby.log. Plik ten jest umieszczony w folderze systemu Derby.

Po uruchomieniu systemu Derby zawartość pliku derby.log jest wymazywana. Można to zmienić ustawiając właściwość derby.infolog.append.

Zamiast używać pliku derby.log można informacje zapisywać do strumienia lub innego pliku. Służą do tego właściwości:

  • derby.stream.error.method
  • derby.stream.error.field
  • derby.stream.error.file

Tworzenie aplikacji

Do działania aplikacji z wbudowaną bazą danych potrzebne są:

  • plik derby.jar
  • biblioteki aplikacji np. w pliku *.jar
  • baza danych
  • opcjonalnie plik derby.properties

Oczywiście aplikacja musi być uruchomiona na urządzeniu posiadającym zainstalowane JRE.

Powyższe składniki można zamienić na tylko dwa:

  • plik derby.jar
  • baza danych

Biblioteki aplikacji i plik derby.properties mogą być umieszczone w bazie danych.

Właściwości systemu

Właściwości dla systemu Derby ustawiamy w pliku derby.properties. Plik ten jest umieszczony w folderze systemu Derby.

Plik zawiera właściwości i parametry konfiguracyjne, które mają zastosowanie do całego systmu Derby.

Plik ten jest tworzony przez użytkownika. Jeżeli pliku nie ma system Derby niezbędne informacje uzupełnia przyjmując wartości domyślne.

Baza danych po połączeniu staje się częścią systemu i dziedziczy ustawienia znajdujące się w pliku derby.properties systemu Derby, do którego należy.

Dokumentacja Derby zaleca aby wszystkie właściwości dla systemu, które można – ustawiać jako właściwości w bazie danych – należy ustawić w bazie danych, a w pliku derby.properties ustawiać tylko te właściwości, których w bazie danych ustawić nie można.

Pliki do ściągnięcia

Aktualny (tworzony narastająco) plik module-info.java

Aktualny (tworzony narastająco) plik DerbyUtil.java

Pliki tworzone narastająco zastępują poprzednie pliki o tej samej nazwie i działają dla wszystkich wcześniej opublikowanych przykładów we wszystkich wpisach w projekcie. W przypadku pliku module-info.java może być potrzebne skreślenie niepotrzebnych wpisów.