5. října 2008

jOpenSpace 2008 - ORM - Hibernate a klientská aplikace

Konečně jsem se dostal k tomu, abych si poslechl audia z akce jOpenSpace. Pro zájemce bych odkázal především na blog otce Fura.

Konference musela být jisto jistě velmi zajímavá a prospěšná. Moc mě mrzí, že jsem se nezúčastnil, ale mohu si za to především sám, protože jsem zasklil call-for-papers v konference java.cz. Dám si závazek, že napřezrok se to již nebude opakovat.

První záznam je z diskuse o ORM. Nosným tématem je použití Hibernate v klientských aplikacích. Problematické v tomto případě je, že Hibernate session object není thread-safe a Hibernate si hodně zakládá na lazy nahrávání čehokoliv (tj. k nahraným objektům je připojena session a atributy, asociace se dohrávají až v okamžiku, kdy je potřeba).

Klientské aplikace napsané v AWT, Swingu nebo SWT mají jedno velké specifikum oproti aplikacím webovým. Tím specifikem je jednovláknovost těchto knihoven. Tj. kód, který přistupuje k UI tak musí činit z UI vlákna (ve webové aplikaci má každý request své vlákno - skoro vždy). Z tohoto vlákna tedy není vhodné provádět náročné akce, protože dojde k zamrznutí UI. A jak v tomto prostředí řešit přístup k datům (pomocí Hibernate a jeho nesynchronizovaného objektu session)?

Varianty jsou v podstatě tři:

  1. používat session pouze z UI vlákna
  2. používat session pouze z jiného vlákna
  3. používat session jak z UI tak z jiného vlákna
První varianta je špatně, protože provádět dlouho trvající dotazy z UI vlákna zhorší odezvu UI. Druhá varianta je ideální, ale má jedno úskalí. Jak zařídit nahrání všech vlastností a vazeb objektu, které budou v UI potřeba tak, aby již nebylo nutné dotahovat žádná data (tj. jak obejít Hibernate laziness). Třetí varianta spočívá v nahrání dat v jiném vlákně a následném nahrání lazy atributů a vazeb z UI vlákna (dotahují se, až když k nim UI přistoupí a to tak učiní z UI vlákna).

Ještě je nutno zmínit jak to bude se správou session objektů. V prvním případě nám stačí jedna session, protože ji používáme pouze z jednoho vlákna. Pro druhý případ může session potřebovat víc, ale ve své podstatě to záleží na počtu výkonných vláken pro provádění komunikace s DB přes Hibernate. Ve třetím případě určitě potřebujeme pro každou událost (řekněme, že se jedná o obdobu requestu v klientské aplikaci) vlastní session, protože ji použijeme pro nahrání objektů a případné další lazy nahrávání z UI vlákna. Tyto 3 strategie je možné komplikovat dodáním synchronizace a využitím menšího počtu session objektů.

Mě osobně se nejvíce zamlouvá druhá varianta, protože veškerá režie s nahráním dat je mimo UI vlákno. Ale jak nahrát vše co je potřeba? Velmi jednoduše. Stačí, aby model každého UI prvku implementoval speciální rozhraní, které bude vracet ty atributy a vazby, které bude pro své vykreslení potřebovat. Díky tomuto kroku a stromové struktuře UI elementů stačí získat tento seznam pro model root elementu (ten se rekurzivně poptá u svých potomků). Inicializaci lazy atributů a vazeb je možné provést pouhým přistoupením k nim pomocí get metod (nebo pomocí metody initialize).

Bohužel klientskou aplikaci jsem již hodně dlouho nedělal, takže tento návrh je pouze z mé hlavy a né z praktické zkušenosti.

3 komentáře:

podlesh řekl(a)...

Jednu swingovskou aplikaci s Hibernate jsem dělal a skutečně jsem použil toto řešení (tedy varianta 2). Nakonec to i fungovalo, ale celkově jsem dospěl k závěru že Hibernate je pro takovéto aplikace naprosto nevhodný.

Anonymní řekl(a)...

TO podlesh:
Nechapu vas prispevek. Jak ORM mapovani v 1 vrstve souvisi se 2 v pripade rich-client nebo 3, tedy thin-client vrstvou? ORM je naprosto nezavisle na pouziti klienta.

Jira řekl(a)...

Já tomu rozumím. Kdyby ORM nepoužívalo lazy loading, pak by skutečně bylo jedno jak to je. Ale pokud lazy loading používá, pak se právě dotahování chybějících atributů a vazeb děje v mimo ORM vrstvu. A tady je ta závislost.

A protože session není synchronizovaná, musí se o ni postarat programátor a zde je problém.