Teda prekladat session jako sezeni, to me vzdycky zvedne ze zidle… Ale jinak dobry popis.
Obsah
Při vývoji aplikací bylo prokázáno, že se programováním kódu, který manipuluje s daty nad databází, zabere až 70% z času, který je pro daný projekt vyhrazen. Někteří odborníci jdou ještě dále a říkají, že se tato hranice pohybuje až někde kolem 90%. Rámec Hibernate poskytuje techniku pro převod dat z objektového modelu do relačního modelu a zpět, a tak dokáže usnadnit práci s daty nad databází a snížit čas potřebný pro naprogramování podobných metod.
Jak jsem již uvedl, Hibernate je nástroj poskytující techniku pro objektově-relační mapování tříd jazyka Java na tabulky relační databáze (ORM). Krom toho, Hibernate poskytuje nástroje, jak s těmito daty manipulovat včetně objektově orientovaného jazyka (HQL), který na základě objektové notace dokáže uložená data z databáze vybírat v podobě objektů.
Hibernate dále poskytuje mechanismy pro transakční zpracování dat, polymorfní perzistenci, kešování, objektově orientované sestavování dotazů, vlastní datové typy a mnoho další funkcionality. Z řadou z nich se seznámíme v následujících podkapitolách. Hibernate poskytuje jednotné API pro práci s řadou databází a databázových serverů.
Aplikační rámec Spring [5] poskytuje podpůrnou funkcionalitu pro snadnou integraci a používání Hibernate společně s ním. Tyto technologie tvoří dvojici, která je v současné době na vrcholu popularity u JEE vývojářů, ale nejen u nich. Hibernate, stejně jako Spring, je vhodnou technologií pro použití i v desktopových aplikacích.
My si přiblížíme ORM nástroj Hibernate právě ve spolupráci s aplikačním rámcem Spring a tuto spolupráci si budeme ilustrovat na naší vzorové aplikaci. Aplikační rámec Spring nabízí podporu pro Hibernate v podobě rozhraní HibernateTemplate, HibernateInterceptor a v podobě Hibernate transakčního manažera. Tuto podporu si popíšeme v relevantních částech následujícího textu.
Následující obrázek ilustruje pozici Hibernate v naší vzorové aplikaci. Zde je potřeba říci, že naše aplikace je založena na třívrstvé architektuře. Jedná se o vrstvy prezentační, aplikační a datovou. Vrstva datová je tvořená sadou tříd, které se starají o manipulaci perzistentních dat nad databází. V našem případě je tato vrstva reprezentována vrstvou přistupující k datům, tzv. DAO vrstvou (Data Access Objects). Tato vrstva jako jediná komunikuje přímo s Hibernate.
Jak si můžeme všimnout, Hibernate je konfigurován pomocí
nastavení uvedených v hibernate.properties a
pomocí XML souborů reprezentujících mapování tříd
na tabulky relační databáze. Hibernate poté komunikuje přímo s
databází pomocí JDBC spojení.
Nyní si představíme útroby Hibernate a popíšeme si, jak tento nástroj funguje. Obrázek zachycuje jednotlivé vrstvy a rozhraní, se kterými bychom se měli seznámit nejdříve, pokud chceme Hibernate používat v naší datové vrstvě.
Hlavní pracovní jednotkou (motorem) Hibernate je sezení. Jedná se o implementaci rozhraní Session. Sezení zapouzdřuje JDBC spojení a představuje konverzi mezi objektovou a relační reprezentací dat. Sezení dále slouží jako továrna pro transakce a udržuje keš první úrovně. Objekty typu sezení je levné vytvořit a uvolnit, protože tohle se děje velmi často, zpravidla minimálně jednou během HTTP požadavku na webovou aplikaci.
Rozhraní Session a Transaction jsou využívána aplikací pro zajistění základních CRUD operací nad databázovými tabulkami. Na obrázku není zobrazené rozhraní Query, které patří na stejnou úroveň jako rozhraní Session a Transaction, a které je voláno v případě potřeby získávání dat z databáze.
Sezení je vytvářeno pomocí továrny sezení (rozhraní SessionFactory). Tato
továrna je konfigurována pomocí nastavení uvedených v
hibernate.properties a obsahuje zkompilované
XML mapování tříd na tabulky relační databáze.
Továrna sezení udržuje keš druhé úrovně. Objekt implementující toto
rozhraní je poměrně drahé vytvořit, proto se v aplikaci většinou
vyskytuje pouze jedna instance tohoto objektu. Pokud aplikace pracuje
nad více databázemi, pro každou z nich musí existovat jedna továrna
sezení.
JDBC spojení pro danou továrnu sezení připravuje poskytovatel spojení. Jedná se o množinu spojení (pool of connections), kterou poskytovatel spojení udržuje a tato jednotlivá spojení následně poskytuje továrně sezení.
Rozhraní Transaction je doporučené API, ale není povinné. Toto transakční API odstiňuje aplikační kód od implementace transakcí na nižší úrovni. Jedná se např. o JDBC transakce nebo JTA. Toto odstínění napomáhá přenositelnosti aplikace. Transakce vytváří transakční továrna. Transakční továrnou rozumíme implementaci rozhraní TransactionFactory. My je poté v aplikaci získáváme z Hibernate sezení.
Na perzistentní třídy Hibernate neklade, na rozdíl od jiných ORM rámců, žádné speciální nároky. Perzistentní třídy jsou obyčejné objekty, které musí obsahovat bezparametrický konstruktor. Je doporučováno, aby tyto třídy poskytovaly jednu vlastnost pro uchování hodnoty primárního klíče. Další omezení nejsou specifikována, takže tyto třídy zpravidla obsahují i další manipulační metody a často také implementují rozhraní Serializable za účelem jejich serializace.
Typickou ukázkou perzistentní třídy je třída
SignPost ze vzorové aplikace, která uchovává
data o odkazech na zajímavé akce, obchody a sportoviště.
public class SignPost implements Serializable {
private String id;
private String link;
...
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
....
}
Abychom nesvazovali aplikační kód s "manuálně" nastavenými
zdroji databázového spojení, poskytuje Spring možnost definovat tyto zdroje skrze jeho aplikační
kontext, viz. aplicationContext-hibernate.xml.
Objekty potom získají odkazy na tyto předem definované zdroje pomocí
klasické syntaxe odkazů na třídy v aplikačním kontextu. Následující
kód ukazuje definice instancí tříd
LocalSessionFactoryBean a
BasicDataSource potřebných pro vytváření
objektů typu Hibernate SessionFactory.
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/sport" />
<property name="username" value="jmeno" />
<property name="password" value="heslo" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="mappingLocations"
value="classpath:/cz/morosystems/sportportal/pojo/*.hbm.xml"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hibernate.generate_statistics">true</prop>
<prop key="hibernate.cache.use_structured_entries">true</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.provider_class">OSCacheProvider</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
</props>
</property>
<property name="dataSource" ref="dataSource"/>
</bean>
Objekt třídy LocalSessionBeanFactory je
zodpovědný za vytváření továrny sezení rámce Hibernate. Třída
LocaleSessionBeanFactory bývá instanciována
jako jedináček a továrny sezení, které produkuje, bývají předávány
pomocí referencí do všech služeb, které je potřebují. Defaultně se
však jedná o proxy objekty, které nechávají tyto služby přistupovat k
datům skrze továrnu sezení a její metodu
getCurrentSession(), ale které mohou
participovat na transakcích řízených aplikačním rámcem Spring. Navíc
může metoda getCurrentSession() pracovat se
sezením řízeným objektem typu
OpenSessionInViewFiltr skrze uživatelské
požadavky. Více o transakcích i třídě
OpenSessionInViewFilter se dozvíme v
podkapitolách 3.3.2. a 3.4.
Na příkladu vidíme možné nastavení továrny sezení, tak jak je máme řešené v naší aplikaci. Tímto
nastavením říkáme, že XML soubory reprezentující
mapování tříd na tabulky databáze se nacházejí v balíku
cz.morosystems.sportportal.pojo a mají příponu
hbm.xml. Říkáme, že používáme databázový server
PostgreSQL a definujeme JDBC ovladač, který
bude komunikaci s tímto serverem obstarávat. Dialekt definuje použitou
syntaxi generovaných SQL dotazů.
Dále říkáme, že do logů se mají vypisovat formátované SQL dotazy, že Hibernate má sbírat data o svém běhu pro potřeby statistik a nastavujeme kešování druhé úrovně a kešování dotazů. Pro keš druhé úrovně definujeme tzv. poskytovatele, který bude naši keš řídit. Stejně jako Hibernate má mnoho dalších voleb, tak i tohoto poskytovatele můžeme dále konfigurovat, ale to již není předmětem této práce.
V této podkapitole jsme se seznámili s ORM nástrojem Hibernate, jeho konfigurací a představili jsme si řadu pojmů, o které se budeme dále opírat. Nyní se podrobně seznámíme s mapováním perzistentních tříd na tabulky relační databáze.