agenda - github...agenda postgresql standard j2ee: jpa co to jest przegląd możliwości mapowanie...
TRANSCRIPT
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
"The world's most advanced open source database"
PostgreSQL
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 SQLDostę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ówHibernate, 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@Entitypublic class Person {
@Id@GeneratedValue(strategy=GenerationType.AUTO)private Integer id;
private String firstName;
private String lastName;
@OneToManyprivate Set<Address> addresses;
protected Person() {}
public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName;
}// ...... setters, getters
}
@Entitypublic class Address {
@Id@GeneratedValue(strategy=GenerationType.AUTO)private Integer id;
private String street;
private String city;
protected Address() {}
public Address(String street, String city) { this.street = street; this.city = city;
}// ...... 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
@Entitypublic class Person { @Id private long id private String name;
private String surname; @Embedded private Address address;...}
@Embeddablepublic class Address {
private String street;private String city;
...}
Entity a dziedziczenieTrzy 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 {}
tabela project
● Mało tabeli
● Nieużywane komórki
● Dobra wydajność gdy dużo klas w hierarchii
● Ryzyko dużego rozrostu 1 tabeli
DTYPE id name budget
L 1 projA 10 000
S 2 projB <null>
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 {}
tabela project
tabela large_project
tabela small_project
DTYPE id name
L 1 projA
S 2 projB
id budget
1 10 000
id
2
Mapowanie dziedziczenia: TABLE_PER_CLASS
@Entity@Inheritance(strategy=
InheritanceType.TABLE_PER_CLASS)public abstract class Project { @Id private long id; ...}
@Entitypublic class LargeProject extends Project { private BigDecimal budget;}
@Entitypublic class SmallProject extends Project {}
tabela project - BRAK
tabela large_project
tabela small_project
id name budget
1 projA 10 000
id name
2 projB
Metody definiowania kwerend
Natywny (zależny od DBMS!) SQLString 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 magFROM Magazine magJOIN mag.articles artJOIN art.author authWHERE auth.firstName = 'John'
Encje muszą być połączone: Magazine List<Article> Author
Do skomplikowanych zapytań pozostają nam podzapytania
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 APIEntityManager 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 static volatile SingularAttribute<Employee, Long> id; public static volatile SingularAttribute<Employee, String> firstName; public static volatile SingularAttribute<Employee, String> lastName; public static volatile SingularAttribute<Employee, 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>
● 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/en-US/html/
● Spring:http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/orm.html
http://www.mkyong.com/tutorials/spring-tutorials/
Źródła