java i bazy danych - jagiellonian universityth-2 java database connectivity (jdbc) to specyfkacja...
TRANSCRIPT
1
1. JDBC
● podstawy,
● transakcje.
2. Mapowanie relacyjno obiektowe.
● Hibernate,
● przykład.
Java i bazy danych
2
Java Database Connectivity (JDBC) to specyfkacja określająca zbiór
klas i interfejsów napisanych w Javie, które mogą być wykorzystane
przez programistów tworzących oprogramowanie korzystające z baz
danych. Implementacja JDBC jest dostarczany przez producentów baz
danych. Jedną z ważniejszych zalet takiego rozwiązania jest ukrycie
przed programistą kwestii technicznych dotyczących komunikacji
z bazą danych. Dzięki temu ten sam program napisany w Javie może
współpracować z różnymi systemami baz danych.
http://docs.oracle.com/javase/tutorial/jdbc/index.html
JDBC - wprowadzenie
3
// zaladowanie klasy z driverem. opcjonalne stworzenie obiektu driveraClass.forName("com.mysql.jdbc.Driver").newInstance();
// utworzenie obiektu java.sql.ConnectionConnection con = DriverManager.getConnection(
"jdbc:mysql://localhost/test?user=monty&password=");
Nazwa klasy ze sterownikiem jak również postać argumentu metody
getConnection() jest uzależniona od używanego RDBMS'a i opisana
w jego dokumentacji (tutaj przykład dla MySQL).
Alternatywa: źródło danych DataSource i usługa JNDI:
Context ctx = new InitialContext();DataSource ds = (DataSource)ctx.lookup("jdbc/MojaDB");Connection con = ds.getConnection("monty", "");
JDBC – połączenie
4
Statement stmt = con.createStatement();
Obiekt java.sql.Statement reprezentuje polecenie. Istnieją jego
rozszerzenia, reprezentujące polecenie z argumentami
(PreparedStatement) czy też wywołanie procedury bazodanowej
(CallableStatement).
JDBC – polecenie
5
Statement stmt = con.createStatement();
Obiekt java.sql.Statement reprezentuje polecenie. Istnieją jego
rozszerzenia, reprezentujące polecenie z argumentami
(PreparedStatement) czy też wywołanie procedury bazodanowej
(CallableStatement).
JDBC – polecenie
6
ResultSet rs = stmt.executeQuery("SELECT * FROM tabela");
Obiekt java.sql.ResultSet umożliwia dostęp do wyników zapytania
(typu SELECT) wysłanego do bazy danych.
while (rs.next()) {
System.out.println(rs.getString("kolumna1"));}
W ramach jednego polecenia (java.sql.Statement) można wykonać
wiele zapytań różnorodnego typu (SELECT, UPDATE, DELETE, ...).
Dostęp do statusu realizacji zapytań (błędy, ilość zmienionych
danych, wygenerowane klucze automatyczne) jest dostępny za
pomocą instancji java.sql.Statement.
JDBC – zapytanie
7
rs.close()
stmt.close();
con.close();
Używane obiekty, jeśli nie będą już wykorzystywane, należy zwalniać
metodą close(). Metody dostępu do baz danych mogą zwracać
wyjątek (java.sql.SQLException), który musi zostać odpowiednio
obsłużony.
JDBC – zwolnienie zasobów
8
JDBC – modele komunikacji
aplikacjaaplikacja
baza danychbaza danych
JDBCJDBC
protokółbazy danych
klient
serwer
aplikacja, applet lub
przeglądarka WWW
aplikacja, applet lub
przeglądarka WWW
serwer aplikacjiserwer aplikacji
JDBCJDBC
baza danychbaza danych
HTTP, RMI, CORBA lub inne wywołanie
protokółbazy danych
klient - GUI
serwer
logika biznesowa
9
Transakcje to zbiór operacji zgrupowanych w jednym lub wielu
obiektach Statement. Aby zakończyć transakcję należy wywołać
metodę commit() na rzecz obiektu Connection. Domyślnie metoda
commit() jest wywoływana po zakończeniu wykonywania zapytań
w ramach jednego obiektu Statement. Aby to zmienić należy użyć
metody setAutoCommit(false). Do anulowania zmian wprowadzonych
przez niezatwierdzoną transakcję służy metoda rollback().
JDBC – transakcje
10
Zwykle w systemy baz danych realizują jednocześnie wiele
transakcji. Aby zapewnić kontrolę nad tym procesem wprowadzono
tzw. poziomy izolacji, poprzez które określa się zasady równoległej
realizacji kilku transakcji. JDBC przewiduje pięć poziomów izolacji:
● TRANSACTION_NONE – brak transakcji.
● TRANSACTION_READ_UNCOMMITTED – dopuszcza odczyt danych przed
wywołaniem metody commit().
● TRANSACTION_READ_COMMITTED – inne transakcje nie mogą odczytywać
zmienionych wierszy przed wywołaniem metody commit() (dirty
reads).
JDBC – poziomy izolacji
11
● TRANSACTION_REPEATABLE_READ – dodatkowo chroni przed sytuacją gdy
transakcja odczytuje wiersz, druga transakcja go zmienia a pierwsza
ponownie go odczytuje otrzymując inne dane (non-repetable reads).
● TRANSACTION_SERIALIZABLE – dodatkowo chroni przed sytuacją, gdy
jedna transakcja odczytuje zbiór wierszy spełniający kryteria zawarte
w warunku WHERE, następnie druga transakcja wstawia wiersz
spełniający ten warunek, po czym pierwsza transakcja ponownie
odczytuje zbiór wierszy dostając nowy rekord (phantom-read).
Poziomy izolacji ustawia się metodą setTransactionIsolation()
wywołaną na rzecz obiektu klasy Connection.
JDBC – poziomy izolacji
12
Obiekt Savepoint (JDBC 3.0) umożliwia częściowe odwrócenie
(rollback) transakcji zamiast całkowitego. Do utworzenia tego
obiektu służy metoda setSavepoint().
Statement stmt = con.createStatement();int rows = stmt.executeUpdate("INSERT INTO AUTHORS VALUES " + "(LAST, FIRST, HOME) 'TOLSTOY', 'LEO', 'RUSSIA'");Savepoint save1 = con.setSavepoint("SAVEPOINT_1");int rows = stmt.executeUpdate("INSERT INTO AUTHORS VALUES " + "(LAST, FIRST, HOME) 'MELVOY', 'HAROLD', 'FOOLAND'");...con.rollback(save1);...con.commit();
JDBC – etapy transakcji
13
Mapowanie relacyjno-obiektowe (ORM) umożliwia zastąpienie
bezpośrednich operacji na bazie danych operacjami na obiektach
javy, reprezentującymi te dane. Operacje bazodanowe, związane z
np. z wyszukiwaniem czy aktualizacją tych obiektów odbywają się
(pół)automatycznie. Najpopularniejszą implementację takiego
mapowania dla języka Java udostępnia biblioteka Hibernate (
http://www.hibernate.org).
Mapowanie relacyjno-obiektowe
14
ORM - przykład
ordersorders
odr_id
odr_date
contractorscontractors
con_id
con_name
con_address
1:N
15
srcdata
Contractor.javaContractorManager.javaContractor.hbm.xmlOrder.javaOrderManager.javaOrder.hbm.xml
utilHibernateUtil.java
Example.javahibermate.cfg.xmllog4j.properties
ORM struktura rzykładu
16
package data;import java.util.HashSet;import java.util.Set;
public class Contractor {private int id;private String name;private String address;private Set orders = new HashSet();
public Contractor(){ // pusty konstruktor
}
public void setId(int id) {this.id = id;
}
public int getId() {return this.id;
}
ORM – Contractor.java
17
public void setName(String name) {this.name = name;
}public String getName() {
return this.name;}
public void setAddress(String address) {this.address = address;
}public String getAddress() {
return this.address;}
public void setOrders(Set orders) {this.orders = orders;
}public Set getOrders() {
return this.orders;}
}
ORM – Contractor.java
18
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>
<class name="data.Contractor" table="contractors"><id name="id" column="con_id">
<generator class="native"/></id><property name="name" column="con_name"/><property name="address" column="con_address"/>
<set name="orders" inverse="true"><key column="con_id"/><one-to-many class="data.Order"/>
</set>
</class></hibernate-mapping>
ORM – Contractor.hbm.xml
19
...public class Order {
private int id;private Date date;private Contractor contractor;
public Order(){ // pusty konstruktor }
public void setId(int id) {this.id = id;
}
public int getId() {return this.id;
}...}
ORM – Order.java
20
...<hibernate-mapping>
<class name="data.Order" table="orders"><id name="id" column="odr_id">
<generator class="native"/></id><property name="date" type="date" column="odr_date"/>
<many-to-one name="contractor" column="con_id"class="data.Contractor" />
</class></hibernate-mapping>
ORM – Order.hbm.xml
21
public class ContractorManager {
public void create(String sName, String sAddress) {Session session = HibernateUtil.getSessionFactory().
getCurrentSession();session.beginTransaction();Contractor c = new Contractor();c.setName(sName);c.setAddress(sAddress);session.save(c);session.getTransaction().commit();
}public Contractor load(int id) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();Contractor c = (Contractor) session.load(
Contractor.class, new Integer(id));session.getTransaction().commit();return c;
}}
ORM – ContractorManager.java
22
package util;
import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;
public class HibernateUtil {private static final SessionFactory sessionFactory;static {
try {// inicjalizacja na podstawie konfiguracji z pliku// hibernate.cfg.xmlsessionFactory = new Configuration().configure().
buildSessionFactory();} catch (Throwable ex) {
System.err.println("failure " + ex);throw new ExceptionInInitializerError(ex);
}}public static SessionFactory getSessionFactory() {
return sessionFactory; }}
ORM – HibernateUtil.java
23
srcdata
Contractor.javaContractorManager.javaContractor.hbm.xmlOrder.javaOrderManager.javaOrder.hbm.xml
utilHibernateUtil.java
Example.javahibermate.cfg.xmllog4j.properties
ORM - struktura rzykładu
24
public class Example {public static void main(String[] args) {
ContractorManager cm = new ContractorManager();if (args[0].equals("create")) {
Contractor c1, c2;cm.create("Adam", "Lesna 11/3");cm.create("Tomasz", "Zielona 123/65");cm.create("Pawel", "Krotka 6");c1 = cm.load(1);c2 = cm.load(2);OrderManager om = new OrderManager();om.create(c1);om.create(c2);om.create(c1);
}
ORM - Example.java
25
else if (args[0].equals("print")) {Order o;Session session = HibernateUtil.getSessionFactory()
.GetCurrentSession();session.beginTransaction();List l = session.createQuery("from Contractor").list();for (int i = 0; i < l.size(); i++) {
Contractor c = (Contractor) l.get(i);System.out.println("Contractor:");System.out.println(c.getId() + ", " + c.getName()) + ", "
+ c.getAddress());for (Iterator it=c.getOrders().iterator(); it.hasNext();){
o = (Order) it.next();System.out.println("Order:"+o.getId()+", "+o.getDate());
}}session.getTransaction().commit();
}HibernateUtil.getSessionFactory().close();
}}
ORM - Example.java
26
<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration><session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver
</property><property name="connection.url">
jdbc:mysql://localhost/example</property><property name="connection.username"></property><property name="connection.password"></property><property name="connection.pool_size">1</property>
ORM - Hibernate.cfg.xml
27
<property name="dialect">org.hibernate.dialect.MySQLDialect
</property><property name="current_session_context_class">
thread</property><property name="cache.provider_class">
org.hibernate.cache.NoCacheProvider</property>
<property name="show_sql">true</property><property name="hbm2ddl.auto">create</property><mapping resource="data/Contractor.hbm.xml"/><mapping resource="data/Order.hbm.xml"/>
</session-factory></hibernate-configuration>
ORM - Hibernate.cfg.xml
28
Niezbędne biblioteki:
antlr.jarasm.jarasm-attrs.jarscglib.jarcommons-collections.jarcommons-logging.jardom4j.jarhibernate3.jarjta.jarlog4j.jarmysql-connector (http://dev.mysql.com/downloads/connector/j/)
Pierwsze uruchomienie programu spowoduje utworzenie
odpowiednich tabel:
java -cp [biblioteki] Example create
ORM - uruchomienie
29
Drugie uruchomienie programu: z pliku hibernate.cfg.xml usuwamy element:
<property name="hbm2ddl.auto">create</property>
java -cp [biblioteki] Example print
Hibernate: select contractor0_.con_id as con1_0_, contractor0_.con_name as con2_0_, contractor0_.con_address as con3_0_ from contractors contractor0_Contractor:1, Adam, Lesna 11/3Hibernate: select orders0_.con_id as con3_1_, orders0_.odr_id as odr1_1_, orders0_.odr_id as odr1_1_0_, orders0_.odr_date as odr2_1_0_, orders0_.con_id as con3_1_0_ from orders orders0_ where orders0_.con_id=?Order: 3, 2006-04-11Order: 1, 2006-04-11Contractor:...
ORM - uruchomienie
30
Podsumowanie
Dostęp do baz danych jest możliwy poprzez interfejs JDBC. Aby z niego
skorzystać, należy pobrać sterownik (bibliotekę jar) dostarczony przez
producenta RDBMS implementującą ten inferfejs. Takie rozwiązanie
zapewnia możliwie dużą niezależność aplikacji od konkretego RDBMS.
Mapowanie relacyjno-obiektowe jest powszechnie wykorzystywane
w aplikacjach klasy enterprise. Przy realizacji dużych projektów,
znacznie upraszcza ono architekturę aplikacji, dodatkowo oddzielając ją
od RDBMS.