Agenda

Transkrypt

Agenda
Agenda
● PostgreSQL
● Standard J2EE: JPA
○
○
○
○
●
●
●
co to jest
przegląd możliwości
mapowanie hierarchii
metody definiowania kwerend
■ Natywny SQL
■ zapytania nazwane
■ JPQL
■ Criteria API
Hibernate
Spring Data
Przykład
Grzegorz Wilaszek, Wojciech Krzystek
PostgreSQL
"The world's most advanced open source
database"
Historia
● początkowo opracowywany na Uniwersytecie
Kalifornijskim w Berkely (Ingres)
● pierwsze wydanie (Postgres95): 1 maja 1995
● obecnie pracuje nad nim organizacja opensource'owa:
PostgreSQL Global Development Group
● wspierany przez komercyjnych dostawców rozwiązań
bazodanowych
● najnowsza wersja: 9.2.4 (4 kwietnia 2013)
Czemu słoń?
Wersja zachodnia i wersja wschodnia:
● Podobno szukano zwierzącego logo. Ktoś
zapropownował słonia.
● Bo słoń zapamiętuje.
Powiązane technologie: slonik, slon, slony
replication (rus. слоны)
Wsparcie systemów operacyjnych i
architekrut
● Systemy operacyjne: Linux (wszystkie niedawne
dystrybucje), Windows(Win2000 SP4 i późniejszy),
FreeBSD, OpenBSD, NetBSD, Mac OS X, AIX,
BSD/OS, HP-UX, IRIX, OpenIndiana, OpenSolaris,
SCO OpenServer, SCO UnixWare, Solaris, Tru64 Unix
● Architekruty: x86, x86-64, IA64 Itanium, PowerPC,
PowerPC 64, S/390, S/390x, SPARC, SPARC 64,
Alpha, ARM, MIPS, MIPSel, M68k, PA-RISC, M32R,
NS32k i VAX
Funkcje składowe w bazie danych
● PL/pgSQL (podobny do proceduralnego języka PL/SQL
w bazie Oracle)
● PL/Python
● PL/Perl
● PL/Tcl
● język SQL
Dostępne do zainstalowania rozszerzenia:
● języki skryptowe: (np. plPHP, PL/Ruby, PL/sh)
● języki kompilowane: C, C++ oraz Java (jako PL/Java);
● język statystyczny R jako PL/R.
Indeksy
● Indeksy funkcyjne - funkcja a nie wartość kolumny
● Indeksy częściowe - dla części tabeli przez dodanie
WHERE na końcu CREATE INDEX
● Możliwość przeglądania indeksów od końca
● "index-only" skany - korzystanie tylko z indeksu
podczas przeglądania bazy
● Przykładowe typy indeksów: B-drzewo, Hash, R-drzewo
i GiST
Wyzwalacze
● Reguły: np. "INSTEAD OF" pozwala wstawić
(INSERT) dane do widoku zamiast do tabeli
● Możliwość definiowania wyzwalaczy na
widokach
Typy danych
● ... standardowe ...
● typy do wyszukiwania pełnotekstowego (tsvector,
tsquery)
● typy geometryczne (point, line, lseg, box, path, polygon,
circle)
● typy adresów sieciowych (cidr, inet, macaddr)
● XML, obsługujący również wyrażenia XPath (od wersji
8.3)
● UUID (od wersji 8.3)
● JSON (od wersji 9.2)
● typy zakresowe (Range Type) (od wersji 9.2)
Ograniczenia wielkości elementów
●
●
●
●
●
●
●
Maksymalny rozmiar bazy: bez ograniczeń
Maksymalny rozmiar tabeli: 32 TB
Maksymalny rozmiar wiersza: 1,6 TB
Maksymalny rozmiar pola w wierszu: 1 GB
Maksymalna liczba wierszy w tabeli: bez ograniczeń
Maksymalna liczba kolumn w tabeli: 250 - 1600 (zależy
od rodzaju kolumn)
Maksymalna liczba indeksów dla tabeli: bez ograniczeń
ORM w Javie
JPA (Java Persistence API)
●
●
pakiety javax.persistence.*
ORM (Object-Relational Mapping)
○
○
tłumaczenie Kompozycji (kolekcje, a nawet mapy!)
tłumaczenie dziedziczenia
●
zwykłe javowe objekty (POJO)
nie czujemy że pracujemy z bazą danych
●
szeroka gama persistence providerów
Hibernate, EclipseLink, ObjectDB, DataNucleus, OpenJPA, ...
●
2 możliwości konfiguracji:
○
○
adnotacje (zaprezentowane tutaj)
pliki konfiguracyjne xml
JPA - Architektura
Wymagania w stosunku do POJO
●
adnotacja javax.persistence.Entity
●
Musi mieć bezargumentowy konstruktor protected, lub public
(Może mieć inne konstruktory)
●
Klasa nie może być final, nie może mieć metod final
(wg. standardu - jenak np. Hibernate sobie z tym radzi)
●
warto zaimplementować Serializable - przesyłanie encji przez wartość do
innego EntityMaganera
●
mogą dziedziczyć po nie-encjach. Mogą być klasach bazowymi nie-encji
●
Persystowane pola encji nie mogą być public. Dostęp jedynie przez gettery
i settery
Strategie łączenia się z bazą
● validate - jeśli na wejściu nie mamy dobrej
schemy to kończymy
● update - dorabiamy to czego brakuje
● create - tworzymy brakujące tabele
● create-drop - jest inaczej ? zrzucamy tabele
Przykładowe persystowane klasy - encje
@Entity
@Entity
public class Person {
public class Address {
@Id
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private Integer id;
private String firstName;
private String street;
private String lastName;
private String city;
@OneToMany
protected Address() {
private Set<Address> addresses;
}
protected Person() {
public Address(String street, String city) {
this.street = street;
}
this.city = city;
}
public Person(String firstName, String lastName) {
// ...... setters, getters
this.firstName = firstName;
this.lastName = lastName;
}
// ...... setters, getters
}
}
Co możemy persystować w klasie ?
●
●
●
●
●
●
●
●
●
prymitywy
typy otoczkowe
enumy
String, BigInteger.
BigDecimal, Date,
Calendar, ...
typy serializowalne
(również user-defined)
inne encje
typy Embeddable →→→
kolekcje powyższych
tablice powyższych
@Entity
public class Person {
@Id
private long id
private String name;
private String surname;
@Embedded
private Address address;
...
}
@Embeddable
public class Address {
private String street;
private String city;
...
}
Entity a dziedziczenie
Trzy strategie:
● SINGLE_TABLE
●
●
(default)
JOINED
TABLE_PER_CLASS
Mapowanie dziedziczenia: SINGLE_TABLE
@Entity
@Inheritance
@DiscriminatorColumn(name="DTYPE")
public abstract class Project {
@Id
private long id;
...
}
@Entity
@DiscriminatorValue(
discriminatorType=STRING, "L")
public class LargeProject extends Project {
private BigDecimal budget;
}
@Entity
@DiscriminatorValue(
discriminatorType=STRING, "S")
public class SmallProject extends Project {
}
DTYPE
id
name
budget
L
1
projA
10 000
S
2
projB
<null>
tabela project
●
●
●
●
Mało tabeli
Nieużywane komórki
Dobra wydajność gdy dużo klas w
hierarchii
Ryzyko dużego rozrostu 1 tabeli
Mapowanie dziedziczenia: JOINED
@Entity
@Inheritance(strategy=InheritanceType.
JOINED)
@DiscriminatorColumn(name="DTYPE")
public abstract class Project {
@Id
private long id;
...
}
@Entity
@DiscriminatorValue(
discriminatorType=STRING, "L")
public class LargeProject extends Project {
private BigDecimal budget;
}
@Entity
@DiscriminatorValue(
discriminatorType=STRING, "S")
public class SmallProject extends Project {
}
DTYPE
id
name
L
1
projA
S
2
projB
tabela project
id
budget
1
10 000
tabela large_project
id
2
tabela small_project
Mapowanie dziedziczenia: TABLE_PER_CLASS
@Entity
@Inheritance(strategy=
InheritanceType.TABLE_PER_CLASS)
public abstract class Project {
@Id
private long id;
...
}
tabela project - BRAK
id
name
budget
1
projA
10 000
tabela large_project
@Entity
public class LargeProject extends Project {
private BigDecimal budget;
}
@Entity
public class SmallProject extends Project {
}
id
name
2
projB
tabela small_project
Metody definiowania
kwerend
Natywny (zależny od DBMS!) SQL
String sqlQuery =
"select night.id nid, night.night_duration, night.night_date,
area.id aid, night.area_id, area.name " +
"from Night night, Area area where night.area_id = area.id " +
"and night.night_duration >= ?";
Query q = getEntityManager().createNativeQuery(sqlQuery,
"GetNightAndArea");
q.setParameter( 1, expectedDuration );
q.getResultList();
JPQL (Java Persistence Query Language)
EntityManager em = getEntityManager();
Query query = em.createQuery(
"select e from Employee e where e.address.city = :city");
query.setParameter("city", "Ottawa");
List<Employee> employees = query.getResultList();
JPQL vs. SQL
●
●
●
●
operujemy na obiektach:
user.address.city.major
brak niektórych słów kluczowch, np: LIMIT
szybkość działania (JPQL pod maską ma SQL)
JOIN nie jest JOINem:
SELECT DISTINCT mag
FROM Magazine mag
JOIN mag.articles art
JOIN art.author auth
WHERE auth.firstName = 'John'
Encje muszą być połączone: Magazine
List<Article>
Do skomplikowanych zapytań pozostają nam podzapytania
Author
Zapytania nazwane (predefiniowane)
Definicja:
@NamedQuery( name="findAllEmployeesInCity",
query="select e from Employee e where e.address.city = :city")
public class Employee {
...
}
Użycie:
EntityManager em = getEntityManager();
Query q = em.createNamedQuery("findAllEmployeesInCity");
q.setParameter("city", "Ottawa");
List<Employee> employees = q.getResultList();
Criteria API vs. JPQL
- "trzeba się uczyć pisania zapytań na nowo"
EntityManager em = getEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
Root<Employee> r = cq.from(Employee.class);
cq.where(cb.equal(r.get(Employee_.address).get(Address_.city), "Ottawa"));
cq.select(r);
TypedQuery<Employee> q = em.createQuery(cq);
List<Employee> employees = q.getResultList();
tymczasem to samo w JPQL:
EntityManager em = getEntityManager();
Query query = em.createQuery(
"select e from Employee e where e.address.city = :city");
query.setParameter("city", "Ottawa");
List<Employee> employees = query.getResultList();
Criteria API - przykład 2
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
Root<Order> r = cq.from(Order.class);
Predicate predicate = cb.and(
cb.equal(r.get(Order_.shipCity), shipCity),
cb.equal(r.get(Order_.freight), freight),
cb.equal(r.get(Order_.shipAddress), shipAddress));
if (countries.size() > 0) {
predicate = cb.and(r.get(Order_.shipCountry).in(Arrays.asList(countries)), predicate);
}
cq.select(r).where(cb.and(cb.equal(r.get(Order_.date), date),
cb.equal(r.get(Order_.employee).get(Employee_.lastName), empLastName),
cb.between(r.get(Order_.orderDate), Util.dayBegin(dateFrom), Utils.dayEnd(dateTo)),
cb.notEqual(r.get(Order_.cancelled), true),
predicate
));
return getEntityManager().createQuery(cq).getResultList();
Criteria API - Metamodel API
EntityManager em = getEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
Root<Employee> r = cq.from(Employee.class);
cq.where(cb.equal(r.get(Employee_.address).get(Address_.city), "Ottawa"));
cq.select(r);
TypedQuery<Employee> q = em.createQuery(cq);
List<Employee> employees = q.getResultList();
przykładowy Metamodel:
@Static Metamodel(Employee.class)
public class Employee_ {
public
public
public
public
}
static
static
static
static
volatile
volatile
volatile
volatile
SingularAttribute<Employee,
SingularAttribute<Employee,
SingularAttribute<Employee,
SingularAttribute<Employee,
Long> id;
String> firstName;
String> lastName;
Address> address;
Criteria API - można i bez metamodelu
Typesafe Criteria Query - potrzebny metamodel:
EntityManager em = getEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
Root<Employee> r = cq.from(Employee.class);
cq.where(cb.equal(r.get(Employee_.address).get(Address_.city), "Ottawa"));
cq.select(r);
TypedQuery<Employee> q = em.createQuery(cq);
List<Employee> employees = q.getResultList();
String-based Criteria Query - bez metamodelu:
EntityManager em = getEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
Root<Employee> r = cq.from(Employee.class);
cq.where(cb.equal(r.get("address").get("city"), "Ottawa"));
cq.select(r);
TypedQuery<Employee> q = em.createQuery(cq);
List<Employee> employees = q.getResultList();
Criteria API - co co się tak męczyć ?
●
●
●
●
●
sprawdzanie typów na etapie kompilacji
sprawdzanie "literówek" w nazwach pól na etapie kompilacji
"No to się zbudowało, to teraz zobaczmy czy działa"
całkowita ochrona przed SQL Injection
wydajniejsze od JPQL (?)
JPA 2.0 (10 grudnia 2009)
● wzparcie dla odwzorowywania kolekcji typów
użytkownika
● wsparcie dla odwzorowywania map
● Embedded
● uporządkowane Listy
● Orphan removal
● Pessimistic Locking
● wzbogacone API EntityMangera
● Cache API
● Criteria API & Metamodel API
● wzbogacenia JPQL
Hibernate framework - JPA provider
●
● pierwsza wersja już w 2001 - JPA (2006) i konkurencja
w powijakach
●
●
●
●
HQL (realizacja JPQL)
Criteria Queries (pierwowzór Criteria API z JPA)
rozbudowania, np: Envers
zaawansowane opcje sterowania wydajnością, np.
Cachem
Spring Data - po co ?
● IoC (DI) container
● w przykładach powyżej getEntityManager() ale jak tę metodę napisać ?
● wysoka testowalność (mockowanie)
● szablony dzięki którym piszemy mniej kodu
● zarządzanie transakcjami
● użyty przez nas: Spring ORM with plain JPA
Praktyka
Ciekawsze fragmenty - obsługa transakcji
przez Springa
@Transactional(readOnly = false,
propagation = Propagation.REQUIRES_NEW)
Person save(Person person);
Ciekawsze fragmenty - usuwanie
public void delete(Person person) {
em.remove(em.merge(person));
}
Ciekawsze fragmenty - usuwanie z listy
public Person deleteAddress(Integer id, Integer addressId) {
Person person = findPersonById(id);
for (Address a : person.getAddresses()) {
if (a.getId().equals(addressId)) {
em.remove(em.merge(a));
person.getAddresses().remove(a);
break;
}
}
return person;
}
Ciekawsze fragmenty - definiowanie list
klasa Person :
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "PERSON_ID", nullable = false)
public Set<Address> getAddresses() {
return addresses;
}
Ciekawsze fragmenty - konfiguracja JPA
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.
PostgresPlusDialect"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="hibernate.ejb.naming_strategy" value="org.
hibernate.cfg.EJB3NamingStrategy"/>
<property name="hibernate.cache.provider_class" value="org.
hibernate.cache.EhCacheProvider"/>
</properties>
Źródła
● PostgreSQL historia, architektura:
http://www.postgresql.org/docs/9.2/static/preface.html
● JPA: http://docs.oracle.com/javaee/6/tutorial/doc/bnbpy.
html
● Criteria:
http://www.objectdb.com/java/jpa/query/criteria/
● Hibernate:
http://docs.jboss.org/hibernate/orm/4.1/manual/enUS/html/
● Spring:
http://static.springsource.org/spring/docs/3.0.x/springframework-reference/html/orm.html
http://www.mkyong.com/tutorials/spring-tutorials/

Podobne dokumenty