agenda - github...agenda postgresql standard j2ee: jpa co to jest przegląd możliwości mapowanie...

41
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

Upload: others

Post on 26-Sep-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 2: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

"The world's most advanced open source database"

PostgreSQL

Page 3: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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)

Page 4: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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. слоны)

Page 5: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 6: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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.

Page 7: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 8: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

Wyzwalacze

● Reguły: np. "INSTEAD OF" pozwala wstawić (INSERT) dane do widoku zamiast do tabeli

● Możliwość definiowania wyzwalaczy na widokach

Page 9: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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)

Page 10: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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ń

Page 11: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

ORM w Javie

Page 12: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 13: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

JPA - Architektura

Page 14: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 15: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 16: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

}

Page 17: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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;

...}

Page 18: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

Entity a dziedziczenieTrzy strategie:● SINGLE_TABLE

(default)● JOINED ● TABLE_PER_CLASS

Page 19: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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>

Page 20: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 21: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 22: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

Metody definiowania kwerend

Page 23: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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();

Page 24: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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();

Page 25: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 26: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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();

Page 27: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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();

Page 28: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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();

Page 29: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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;}

Page 30: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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();

Page 31: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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 (?)

Page 32: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 33: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 34: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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

Page 35: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

Praktyka

Page 36: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

Ciekawsze fragmenty - obsługa transakcji przez Springa

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)Person save(Person person);

Page 37: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

Ciekawsze fragmenty - usuwanie

public void delete(Person person) { em.remove(em.merge(person));}

Page 38: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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;

}

Page 39: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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;}

Page 40: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

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>

Page 41: Agenda - GitHub...Agenda PostgreSQL Standard J2EE: JPA co to jest przegląd możliwości mapowanie hierarchii metody definiowania kwerend Natywny SQL ... Historia początkowo …

● 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