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/