Java Database Connectivity

Z Wikipedie, otevřené encyklopedie
Skočit na: Navigace, Hledání

V tomto článku byl použit překlad textu z článku Java Database Connectivity na anglické Wikipedii.

Java Database Connectivity (známé spíše jako JDBC) je API pro programátory v programovacím jazyku Java, které definuje jednotné rozhraní pro přístup k relačním databázím. JDBC je součástí Javy SE („Standard Edition“) od JDK 1.1. Pro přístup ke konkrétnímu databázovému serveru je potřeba JDBC driver (ovladač), který poskytuje tvůrce databázového serveru.

Úvod[editovat | editovat zdroj]

JDBC API vzniklo jako vrstva mezi Java aplikací a vlastní komunikací s databází. Datové typy SQL lze získat z výsledku SQL dotazu jako instance Java tříd a s těmi pracuje aplikace. Naopak JDBC ovladač (driver) dokáže vkládat instance Java tříd do SQL dotazů a správně, v závislosti na zvolené databázi, je uložit, upravit apod. Takto lze vytvořit aplikaci nezávislou na zvoleném databázovém stroji. Nicméně je stále potřeba psát dotazy v SQL - naproti tomu stojí Hibernate.

Historie a implementace[editovat | editovat zdroj]

JDBC bylo poprvé uveřejněno společností Sun Microsystems jako součást JDK 1.1 19.února 1997. Od té doby je standardní součástí Java Standard Edition. Třídy knihovny JDBC jsou uloženy v balíčku knihoven jazyka Java java.sql a javax.sql.

Od verze 3.0 je JDBC vyvíjen pod hlavičkou Java Community Process. JSR 54 obsahuje specifikaci pro JDBC 3.0 (který je součástí J2SE 1.4), JSR 114 specifikuje implementaci rozhraní Rowset v JDBC a JSR 221 je zahrnuje specifikaci pro JDBC 4.0, jako součást Java SE 6.

Funkčnost[editovat | editovat zdroj]

JDBC umožňuje paralelní použití několika implementací v jediné aplikaci. API poskytuje možnost dynamického načtení příslušných Java knihoven a jejich registraci pomocí JDBC Driver Manager. Driver Manager obsahuje tovární metodu pro vytvoření připojení s databází přes JDBC. Připojení k databázi přes JDBC umožňuje tvorbu a vykonání jednotlivých příkazů. Patří mezi ně SQL příkazy pro modifikaci dat: CREATE, INSERT, UPDATE a DELETE a také dotazovací příkaz SELECT. JDBC připojení také umožňuje přístup k uloženým procedurám. Používání jednotlivých příkazů je specifikováno v následujících rozhraních:

  • Statement - příkaz je vždy odeslán databázovému serveru
  • PreparedStatement - příkaz je uložen a následně je stanoven postup pro jeho vykonání přímo na databázovém serveru. Toto rozhraní umožňuje několikanásobné vykonání stejného příkazu efektivním způsobem.
  • CallableStatement - používá se pro vykonání uložené procedury nad databází.

Příkazy pro modifikaci dat jako INSERT, UPDATE a DELETE vrací hodnotu, která uvádí, kolik řádků bylo v databázi pozměněno. Tyto příkazy dále nevrací žádnou další informaci.

Dotazovací příkazy vrací JDBC řádek s množinou výsledků. Řádek s množinou výsledků se používá k přenesení množiny výsledků. Jednotlivé sloupce jsou v řádku označeny pomocí jména nebo čísla sloupce. Množina výsledků může obsahovat libovolný počet řádků. Dále také obsahuje metadata, která identifikují jména jednotlivých sloupců a jejich datových typů.

Rozšíření pro základní verzi JDBC API je obsaženo v knihovně javax.sql.

Připojení přes JDBC jsou většinou zprostředkovány pomocí návrhového vzoru fond (anglicky connection pool), zřídkakdy jsou získány přímo skrze ovladač. Příklady připojovacích fondů jsou například:

Přístup k databázi[editovat | editovat zdroj]

Související informace naleznete také v článku JDBC Driver.

Identifikace databáze se děje na základě URI, Unified Resource Identifier. Formát tohoto URI je závislý na zvoleném JDBC driveru:

Příklady JDBC URI:

  • MySQL: jdbc:mysql://server/jméno_databáze?characterEncoding=UTF-8
  • Sybase: jdbc:sybase:Tds:server:port/jméno_databáze
  • IBM AS400: jdbc:as400://server/jméno_databáze
  • Oracle: jdbc:oracle:thin:@server:port:jméno_databáze

JDBC driver je klientský adaptér, který převádí požadované příkazy z Java aplikací do protokolu, který využívá Systémem řízení báze dat.

Typy[editovat | editovat zdroj]

Existují jak placené tak freeware ovladače použitelné pro většinu relačně databázových serverů. Každý jednotlivý ovladač je možno zařadit do jednoho z následujících typů:

  • Typ 1, který zavolá původní kód lokálně přístupného ODBC driveru.
  • Typ 2, který zavolá původní knihovnu od výrobce příslušného databázového systému přímo na straně klienta. Tento kód poté komunikuje s danou databází pomocí sítě.
  • Typ 3, ovladač výhradně určený pro Javu, který komunikuje se serverovou stranou pomocí prostředníka, který dále komunikuje s příslušnou databází.
  • Typ 4, ovladač výhradně určený pro Javu, který využívá původní databázový protokol.

Mimo jiné existuje také tzv. internal JDBC driver, který je spolu s JRE zařazený v SQL databázích přístupných pro Javu. Tento ovladač se používá pro Java uložené procedury. Zmíněný typ ovladače se nedá přímo určit podle zařazení uvedeného výše, nejvíce se podobá ovladači typu 2, případně typu 4 (záleží na tom, zdali je příslušná databáze implementována přímo v Javě, či nikoli). Příkladem takového typu ovladač je KPRB vydaný společností Oracle. "jdbc:default:connection" je víceméně standardní způsob jak vytvořit dané připojení (je podporovaný např. Oracle a Apache Derby). Jeho výhoda spočívá v tom, že JDBC klient vlastně funguje jako součást databáze, se kterou chceme pracovat, takže přímý přístup je používanější nežli přístup skrze síťové protokoly.

Příklady JDBC driverů[editovat | editovat zdroj]

  • MySQL: com.mysql.jdbc.Driver
  • Sybase: com.sybase.jdbc3.jdbc.SybDriver
  • IBM AS400: com.ibm.as400.access.AS400JDBCDriver
  • Oracle: oracle.jdbc.driver.OracleDriver

Samozřejmostí je autentizace uživatelským jménem a heslem.

Příklad[editovat | editovat zdroj]

Metoda Class.forName(String) se používá k načtení třídy JDBC driver. Řádka kódu dole znázorňuje načtení JDBC driveru od jistého poskytovatele (some jdbs vendor). Některé JVM také požadují, aby byla příslušná třída zavedena pomocí metody .newInstance().

Class.forName("com.somejdbcvendor.TheirJdbcDriver");
public void connect() throws DriverNotFoundException, ConnectionFailedException {
    try {
        Class.forName(jdbcDriver);
        connection = DriverManager.getConnection(dbURI, user, passwd);
    } catch (ClassNotFoundException e) {
        throw new DriverNotFoundException(e.getMessage());
    } catch (SQLException e) {
        throw new ConnectionFailedException(e.getMessage());
    }
}

Nezapomínejte uzavírat navázaná spojení!

public void disconnect() throws DisconnectFailedException {
    try {
        connection.close();
    } catch (SQLException e) {
        throw new DisconnectFailedException(e.getMessage());
    }
}

Od verze JDBC 4.0 není již nutné explicitně načítat JDBC drivery pomocí Class.forName(). Pro více informací klikněte na JDBC 4.0 Enhancements in Java SE 6.

Když je driver načten, je vytvořena jeho vlastní instance, která je dále zaregistrována pomocí třídy Driver manager. Proto je nezbytné ve třídě příslušného driveru zahrnout potřebný kód ve statickém inicializačním bloku, např. DriverManager.getConnection()

Nyní, když je třeba vytvořit JDBC připojení, použijeme jednu z metod DriverManager.getConnection().

Connection conn = DriverManager.getConnection(
     "jdbc:somejdbcvendor:other data needed by some jdbc vendor",
     "myLogin",
     "myPassword");
try {
     /* you use the connection here */
} finally {
    //It's important to close the connection when you are done with it
    try {
        conn.close();
    } catch (Throwable ignore) {
        /* Propagate the original exception instead of this one that you may want just logged */
    }
}

Použitá URL závisí na příslušném JDBC driveru. Vždy začíná "jdbc:"protokol, avšak zbytek závisí na jednotlivých výrobcích DB systémů. Když je vytvořeno připojení, musí následovat vytvoření příkazu.

Statement stmt = conn.createStatement();
try {
    stmt.executeUpdate("INSERT INTO MyTable(name) VALUES('my name')");
} finally {
    //It's important to close the statement when you are done with it
    try {
        stmt.close();
    } catch (Throwable ignore) {
        /* Propagate the original exception instead of this one that you may want just logged */
    }
}

Je důležité povšimnout si faktu, že Připojení (Connections), Příkazy (Statements) a Množiny Výsledků (ResultSets) často vytěžují operační systém, především sockety a popisovač souborů. V případě připojení ke vzdáleným databázovým serverům jsou vytěžovány i další součásti serveru jako např. ukazatele na současně otevřené Množiny výsledků. Je tedy nezbytně nutné zavřít (pomocí close()) jakýkoli JDBC objekt, který již není třeba; programátor by neměl spoléhat pouze na Garbage collector. Pominutí správného použití metody close() vede k nežádoucím chybám a nesprávnému chodu programu. Při práci s JDBC objekty je doporučeno používat vzorovou konstrukci try-finally (použita též v kódu nahoře).

Data jsou získána z databáze použitím databázového mechanizmu dotazů. Na následujícím příkladu je znázorněno vytvoření příkazu (Statement) a vykonání příslušného dotazu.

Statement stmt = conn.createStatement();
try {
    ResultSet rs = stmt.executeQuery("SELECT * FROM MyTable");
    try {
        while (rs.next()) {
            int numColumns = rs.getMetaData().getColumnCount();
            for (int i = 1; i <= numColumns; i++) {
               // Column numbers start at 1.
               // Also there are many methods on the result set to return
               //  the column as a particular type. Refer to the Sun documentation
               //  for the list of valid conversions.
               System.out.println("COLUMN " + i + " = " + rs.getObject(i));
            }
        }
    } finally {
        try { rs.close(); } catch (Throwable ignore) { /* Propagate the original exception
instead of this one that you may want just logged */ }
    }
} finally {
    try { stmt.close(); } catch (Throwable ignore) { /* Propagate the original exception
instead of this one that you may want just logged */ }
}

Pokud dojde k selhání databázové operace, JDBC vyvolá SQLException. Obvykle existuje velmi málo možností, jak zotavit program z takové chyby, kromě co nejdetailnějšího logování. Je doporučeno přeložit SQLException do Application Domain Exception, která v tomto případě vede k návratu do stavu před chybnou transakcí (transaction rollback) a k upozornění uživatele.

Příklad databázové transakce:

boolean autoCommitDefault = conn.getAutoCommit();
try {
    conn.setAutoCommit(false);
 
    /* You execute statements against conn here transactionally */
 
    conn.commit();
} catch (Throwable e) {
    try { conn.rollback(); } catch (Throwable ignore) {}
    throw e;
} finally {
    try { conn.setAutoCommit(autoCommitDefault); } catch (Throwable ignore) {}
}

Zde jsou příklady typů hostitelské databáze, do kterých je umí převést Java pomocí svých metod:

setXXX() Methods
Oracle Datatype setXXX()
CHAR setString()
VARCHAR2 setString()
NUMBER setBigDecimal()
setBoolean()
setByte()
setShort()
setInt()
setLong()
setFloat()
setDouble()
INTEGER setInt()
FLOAT setDouble()
CLOB setClob()
BLOB setBlob()
RAW setBytes()
LONGRAW setBytes()
DATE setDate()
setTime()
setTimestamp()

Pro znázornění použití příkazu pro práci s uloženou procedurou (CallableStatement) navštivte JDBC API Guide.

Související články[editovat | editovat zdroj]

Externí odkazy[editovat | editovat zdroj]