2009-09-20

Využití UJO v Hibernate

Tento článek se zabývá využitím UJO objektů v prostředí ORM frameworku Hibernate. Jaký může být důvod nahradit klasické POJO objekty invazivnější alternativou? Výhodu vidím především v možnostech snadnějšího zpracování výsledků pomocí užitečného API a k tomu přijde vhod i jisté navýšení výkonu některých typů HQL dotazů.

Úvodem bych rád rozptýlil mýtus, že za UJO objekty je schovaná neprůhledná magie. UJO může být každý objekt, který implementuje interface Ujo se čtyřmi metodami. Existuje více implementací, ale nyní si popíšeme QuickUjo obsažený v UJO Frameworku 0.91, který se vyznačuje snadnou použitelností a velkou rychlostí čtení i zápisu ve srovnání s Java reflexí.

Jak ten QuickUjo tedy funguje, ptáte se? Uvnitř toho objektu je schovaný jediný atribut obsahující pole objektů s délkou odpovídající počtu atributů objektu. Protože pro přístup k hodnotám objektu slouží konstanty zvané UjoProperty, můžeme každé takové property přiřadit index ukazující na jednu buňku z tohoto pole. Pokud tedy máme instanci UJO + UjoProperty, tak můžeme snadno získat i hodnotu, o přetypování se pak postará implementace UjoProperty. Není to jednoduché?

Typický příklad kódu pro čtení hodnoty:
String name = Person.NAME.getValue(person);
alternativní příklad použití rozšířené implementace QuickUjoMid:
String name = person.get(Person.NAME);

Zajímavé bude srovnání výkonu UJO a POJO objektů v prostředí ORM frameworku Hibernate, potřebujeme však znát, jak se ty UJO mapují. Můj kolega Tomáš Hampl, napsal elegantní řešení založené na implementaci rozhraní PropertyAccessor, které je nyní k dispozici v UJO Frameworku 0.91. Vlivem nedokonalosti Hibernate je třeba implementovat ještě odpovídající gettery, ty však Hibernate používá pouze při startu aplikace. Nic nám ovšem nebrání dopsat si také settery pro vlastní pohodlí a objekty používat jako běžné POJO. Ukázka hotové implementace UJO je tady.

Specifikace alternativního accessoru v HBM souboru vypadá takto:
<hibernate-mapping
default-access = "org.ujoframework.hibernateSupport.UjoPropertyAccessor"
... >


Pokud se výdáte cestou anotací, použijte
@org.hibernate.annotations.AccessType( "org.ujoframework.hibernateSupport.UjoPropertyAccessor" )

a na místo fieldů anotujte gettery.
Podívejte se, jak dopadly benchmark testy:

Hibernate akcePOJO [sec]
UJO [sec]Poměr
INSERT11,3712,310,92
SINGLE SELECT0,580,521,13
EMPTY SELECTS152,5394,301,62
MULTI SELECT169,5294,721,79
UPDATE3,693,750,99
DELETE210,14140,271,50

Kompetentní výklad výsledků přenechám raději odborníkům na Hibernate v diskusi. Popis testovacího prostředí najdete tady. Zdrojový kód testu lze stáhnout na SourceForge.

Na závěr bych rád uvedl na pravou míru, že reálné navýšení rychlosti se projeví především u rychlých a dobře indexovaných SQL dotazů s přiměřenou mírou aplikační logiky. Pokud je odezva na SQL dotaz pomalá a nebo výsledek dotazu podléhá náročnému zpracování, úspora rychlosti se v kontextu ostatních událostí může vytratit.

Odkazy:

1 komentář:

Anonymní řekl(a)...

dobry start