Obsah
import java.sql.*;
public class TestJDBCMySQL {
public static void main(String[] args) {
String url = "jdbc:mysql://idealab.cs.uiowa.edu/WorksOn";
String uid = "user";
String pw = "testpw";
try { // Load driver class
Class.forName("com.mysql.jdbc.Driver");
} catch (java.lang.ClassNotFoundException e) {
System.err.println("ClassNotFoundException: " +e);
}
...
...
Connection con = null;
try {
con = DriverManager.getConnection(url, uid, pw);
Statement stmt = con.createStatement();
ResultSet rst = stmt.executeQuery("SELECT ename,salary FROM Emp");
System.out.println("Employee Name,Salary");
while (rst.next()) {
System.out.println(rst.getString("ename")+","+rst.getDouble("salary"));
}
con.close();
} catch (SQLException ex) {
System.err.println("SQLException: " + ex); }
}
}
JDBC je velmi obecné rozhraní pro přístup k relačním databázím. Proto:
je "slabě typované", nemá např. speciální metody pro jednotlivé typy SQL dotazů, vše se spouští executeQuery.
totéž platí pro přístup k výsledkům dotazů: ResultSet je jednoduchý iterátor (přesněji kurzor), kde lze z aktuální pozice číst a případně na ní modifikovat.
vše podstatné je ponecháno na uživateli - formulaci SQL dotazů uvnitř execute, executeQuery apod. - rozhraní nezkontroluje ani syntaktickou správnost, to až samotný DB stroj.
taktéž výjimky jsou téměř vždy pouze SQLException s textovým popisem uvnitř
Klasickým způsobem práce s JDBC je tento postup:
získáme spojení typicky oslovením DriverManageru s uvedením url zdroje, jména a hesla uživatele:
con = DriverManager.getConnection(url, uid, pw);
na získaném spojení vytváříme příkazy (Statement):
Statement stmt = con.createStatement();
na příkazu spustíme SQL dotaz:
ResultSet rst = stmt.executeQuery("SELECT ename,salary FROM Emp");
výsledky dotazu projdeme iterací výsledného ResultSetu:
while (rst.next()) {
System.out.println(rst.getString("ename")+","+rst.getDouble("salary"));
}
spojení "po použití" uzavřeme.
Implicitně se pro zřízené spojení nastaví režim "auto-commit", každý dotaz je uzavřen do samostatné transakce.
Chceme-li toto změnit (což je vzhledem k výkonu i vhodné), nastavíme con.setAutoCommit(false) a řídíme si transakce sami.
Příklad kódu s řízením transakce: první změna je potvrzena (commit), druhá zamítnuta (rollback):
con.setAutoCommit(false);
// inserts first two messages
for (int i = 0; i < messages.length-1; i++) {
stmt.executeUpdate(
"INSERT INTO MESSAGES VALUES (" ... ")");
con.commit();
// inserts last message ?
stmt.executeUpdate(
"INSERT INTO MESSAGES VALUES (" ... ")");
// no. last message will not be inserted!
con.rollback();
Na rychlé a nenáročné vyzkoušení databázových věcí v Javě můžeme použít volně dostupný javový systém řízení báze dat HSQLDB (dříve HypersonicSQL), http://hsqldb.sf.net.
Všechny demoprogramy dostupné ve zdrojové podobě jsou bez úprav učené pro HSQLDB.
HSQLDB může pracovat ve třech režimech:
běží v rámci procesu klientského programu, není nutné spouštět zvlášť, pouze v programu přistoupíme k databázi pomocí zvláštního URL - viz manuál HSQLDB nebo příklady
DB server běží zvlášť, tudíž je přístupný více klienty, tabulky se ukládají na disk
dtto, přístupné přes HTTP přes mini HTTP-server
Předpřipravené příkazy (Prepared Statements) jsou prostředkem, jak efektivně provádět často opakované SQL dotazy, např.:
Technicky předpřipravený dotaz vypadá tak, že na místě dosazovaného parametru je znak ?.
Pomocí set-metod se daný formální parametr ("otazník") nahradí skutečnou hodnotou a pak se příkaz spustí.
// příprava příkazu
PreparedStatement pstmt = con.prepareStatement(
"SELECT E.FIRSTNAME, E.SURNAME, M.CREATED, M.TEXT " +
"FROM EMPLOYEES AS E, MESSAGES AS M " +
"WHERE E.SURNAME = ?"
+" AND E.ID = M.TO " +
"ORDER BY M.CREATED DESC");
// naplnění parametrů
pstmt.setString(1, "Novak");
// vlastní provedení
ResultSet result = pstmt.executeQuery();
Uložené procedury - Stored Procedures - jsou vzdáleně podobné předpřípraveným příkazům, jsou však zcela v server-side režii.
Běží tedy vzdáleně přímo na serveru.
Jsou výhodné nejen z hlediska výkonu, ale i údržby - jsou centralizovaně uložené, lze je lépe měnit při změnách datového modelu, konfigurace DB atd.
Podporuje-li to daný DBMS, můžeme řádky vrácených tabulek modifikovat:
ResultSet result = stmt.executeQuery(
"SELECT TEXT " +
"FROM MESSAGES " +
"WHERE ID > 10");
// posuň se na pátý řádek výsledku
result.absolute(5);
// změň hodnotu atributu/pole
result.updateString("TEXT", "Zmeneny text zpravy");
// proveď změny
result.updateRow();
DBMS poskytne základní informace o
DatabaseMetaData dbmd = con.getMetaData();
// základní údaje o DBMS
System.out.println(
"DBMS: " +
dbmd.getDatabaseProductName() + ", " +
dbmd.getDatabaseProductVersion() );
// údaje o driveru
System.out.println(
"Driver: " +
dbmd.getDriverName() + ", " +
dbmd.getDriverVersion() );
// dostupné funkce DBMS
System.out.println("String functions: "+dbmd.getStringFunctions());
System.out.println("TimeDate functions: "+dbmd.getTimeDateFunctions());
System.out.println("Numeric functions: "+dbmd.getNumericFunctions());
System.out.println("System functions: "+dbmd.getSystemFunctions());
Moderní přístup k datovým zdrojům je založen na přidání další úrovně adresovací abstrakce:
místo URL databáze, jména a hesla se
prostřednictvím jmenné a adresářové služby (JNDI) najde datový zdroj - aplikační programátor ani předem neví, kde je zdroj fyzicky uložen, jaký DBMS se o něj stará
datový zdroj se zpřístupní nikoli jako Connection, ale ponovu jako javax.sql.DataSource
teprve z něj se získá spojení.
JDO je specifikace, která prochází tzv. Java Community Process (JCP) Program, blíže viz http://jcp.org.
Mají na ni tedy vliv i nezávislí vývojáři.
Její aktuální platná verze je 1.0.1, připravuje se 2.0.
Specifikace JDO 1.0.1 má 200 stran.
Motivací pro JDO bylo dát pohodlnější techniku (než JDBC a serializace) pro zachycení stavu běžných javových objektů v programu a možnost jeho obnovy.
Existuje několik open-source i komerčních implementací JDO:
komerční implementace JDO, dostupná na http://www.solarmetric.com/
Popis: Kodo JDO is SolarMetric's robust, high-performing, feature-rich implementation of the Java™ Data Objects specification for transparent persistence. Unlike many proprietary object/relational mapping tools, Kodo JDO provides access to relational databases through the JDO standard, enabling Java developers to use existing relational database technology from Java without needing to know SQL or be an expert in relational database design. It can be used with existing database schemas, or can automatically generate its own schema.
open-source, free (BSD-like licence), dostupný na http://www.castor.org/jdo.html
open-source, free implementace, dostupná na http://tjdo.sourceforge.net/. Charakteristika:
Supports JDO 1.0.1. Implements the entire JDOQL query language, including several useful method enhancements. Auto-creates all necessary schema elements (tables, foreign keys, indexes) according to your app's classes and JDO metadata. Auto-validates expected schema structure at runtime, reducing failures from schema evolution. Can map Java classes to SQL views, and allows for direct SQL queries, to leverage SQL capabilities not normally accessible through JDO. Designed to be lightweight and fast.
Java Data Objects - informace na stránkách Sun
JDO Central.com - hlavní portál o JDO
Alternativou pro pohodlnou serializaci mnoha typů objektů do XML je např. open-source balík XStream, viz dále.
převádějí do binární podoby všechny instanční proměnné
vyjma těch označených klíčovým slovem transient
Tak lze zajistit serializaci skutečně jen potřebných složek stavu objektu, zbytek se po deserializaci může "dopočítat".
Požadujeme-li speciální chování (např. kvůli serializaci návazných/odkazovaných objektů), můžeme v objektu poskytnout metody:
realizuje zápis objektu do výstupního proudu - metodu si napíšeme sami
realizuje čtení objektu ze vstupního proudu - metodu si napíšeme sami
Serializační mechanizmus zajistí vytvoření "prázdného" objektu, ten pak naplníme metodou readObject.
Potřebujeme-li serializaci javových objektů jen na prosté účely typu
uložení a opětovné načtení konfigurace do/ze XML souboru
přenesení objektů jinému procesu, programu, na jiný stroj
pak je XStream pravděpodobně nejlepší volbou, pokud nám nevadí nepodpora non-ASCII znaků...
XStream je extrémně jednoduše a přímočaře použitelné API pro serializaci jakýchkoli objektů do XML.
Není třeba psát žádné popisovače, stačí vybrat objekt a poslat ho metodě toXML objektu serializátoru org.codehaus.xstream.XStream.
Vytvoříme pole se zadaným počtem prvků, postupně do něj vřadíme nově vytvořené objekty Person a toto pole serializujeme.
public static int LEN = 10000;
public static void main(String[] args) {
Person[] people = new Person[LEN];
XStream xs = new XStream();
xs.alias("person", Person.class);
for(int i = 0; i < LEN; i++) {
people[i] = new Person("Clovek "+i, i, i * 10);
}
// serialize
String xml = xs.toXML(people);
System.out.println(xml);
// uncomment the following code to test deserialization
/*
Person[] secondPeople = (Person[])xs.fromXML(xml);
for(int i = 0; i < secondPeople.length; i++) {
increaseSalary(secondPeople[i], 20);
}
*/
}