ponedeljek, 7. april 2008

Named SQL queries

Hibernate je ena tako zelo zanimiva stvarca. Zadnje čase veliko delam z njim in ga vedno bolj spoštujem kot produkt in rešitevlja v težkih trenutkih razvoja programske opreme. Danes bi rad napisal nekaj o sposobnosti Hibernate-a, da izvaja nativne SQL poizvedbe, pod lastnim okriljem (znotraj Hibernate-a). Lastnost je zelo koristna, v primeru, da je potrebno sestaviti SQL poizvedbo, ki je kompleksna iz zapis v HQL ali pa enostavno naredi nekaj posebnega. Zadnje čase se sam zatekam k tej metodi, ker enostavno nimam modeliranih vseh tabel, ki jih uporabljam pri poizvedbah. Ne da se mi modelirat vseh tabel, ki jih uporabljam. (Dolga zgodba: baza ni niti približno programerju prijazna...).
Tako sem začel polniti svoje "mapping" datoteke z SQL poizvedbami, ki sem jih opisal v Hibernate-u razumljiv način.
Primere bom jemal iz uradne Hibernate dokumentacije za Named SQL queries.
Pa poglejmo prvi primer:
<sql-query name="mySqlQuery">
<return-scalar column="name" type="string"/>
<return-scalar column="age" type="long"/>
SELECT p.NAME AS name,
p.AGE AS age,
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
</sql-query>

Primer opisuje SQL poizvedbo poimenovano mySqlQuery, ki ima dva stolpca name in age, s svojima podatkovnima tipoma. Podatkovni tipi so Hibernate podatkovni tipi: obstaja logična preslikava v Java podatkove tipe, seveda se lahko uporablja tudi direktno Java podatkovni tip, npr. namesto string bi lahko bil java.lang.String. Takšna poizvedba, je "veljavna" Hibernate poizvedba in jo lahko vključimo v druge dele Hibernate nivoja - Hibernate pozna vhod in izhod. Hitro sem se navadil na tak način dela, ker je dokaj enostavno. V priljubljenem orodju za delo z SQL-om, sestavim poizvedbo, kopiram v mapirno datoteko. Povem kaj je vhod in izhod in sem gotov.
Pa poglejmo, kako povem Hibernate-u, kaj naj pričakuje kot vhod.
<sql-query name="mySqlQuery">
<return-scalar column="name" type="string" />
<return-scalar column="age" type="long" />
SELECT p.NAME AS name,
p.AGE AS age,
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
AND p.AGE = :age
<query-param name="age" type="long" />
</sql-query>

Tako, parameter je age. Vse zapisano se uporablja v Java kodi na sledeč način:

Query query = null;
query = this.getSession().getNamedQuery("mySqlQuery");
query.setString("prdId", prdId.toString());

Object objResult = null;
objResult = query.uniqueResult();
// ...
Do sem vse lepo in prav. Delo na ta način je zelo prijetno in olajša delo. Bolj ko postanejo poizvedbe zahtevne in obseže, bolj pride v poštev komentiranje kode (kot vedno). Pa poglejmo primer (da se izognem XML formatiranju, bom pisal samo SQL poizvedbo):

-- Prebere ime in starost oseb z imeni, ki se začnejo na Hiber
SELECT p.NAME AS name,
p.AGE AS age,
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'

Če to izvedem v priljubljenem SQL orodju, deluje enako kot prej. Deluje tudi v Hibernate okolju. Pa če rečemo, da postane koda še bolj kompleksna in malo nejasna, opišemo svoje mnenje z dodatnimi komentarji.

-- Prebere ime in starost oseb z imeni, ki se začnejo na Hiber
-- Je to polje prvo ime ali priimek ?
SELECT p.NAME AS name,
p.AGE AS age,
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'

Za potrditev kopiramo poizvedbo v priljubljeno SQL orodje in poženemo. Dobim identičen rezultat. Kopiram v Hibernate mapirno datoteko (prvi primer) in na veliko presenečenje dobim veliko sočno, nelogično izjemo:

org.hibernate.QueryException: Expected positional parameter count: 1, actual parameters: [] [-- Prebere ime in starost oseb z imeni, ki se začnejo na Hiber
-- Je to polje prvo ime ali priimek ?
SELECT p.NAME AS name,
p.AGE AS age,
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'] ...

Sledi obilo solate. V zmedi, kopiram poizvedbo v SQL orodje, poženem in dela. Prenesem nazaj, poženem in ne dela. Prosim?
Hja. Pridemo spet do tega: kaj za koga kaj pomeni oz. pride do očitne težave: kaj bi naj bilo in kaj dejansko je.
Povedano na kratko: Hibernate je vprašaj (?) v komentarju razumel kot pozicioniran parameter in ne kot del komentarja. Vrednosti za najden paremter pa ni najdel. Torej sledi edina logična rešitev: izjema.
Ne vem, če je to napaka ali lastnost Hibernate-a, meni se vsekakor zdi, da je to napaka. A kaj čmo, tako pač je. V dokumentaciji nisem (do sedaj) še nič najdel na to temo, tako da ne znam povedati nič več.

Le toliko za opomnik, da ne bo potrebnega toliko časa, kot sem ga potreboval jaz; da sem razrešil to skrivnost. Naj povem, da so poizvedbe, ki jih imam napisane več 100 vrstic dolge, tako da ni bilo tako preprosti poiskati težav; kot so očitne v primeru, ki sem za zapisal. Da sem rešil ta problem, sem potreboval dobro uro: to je pa res zadnja stvar, ki sem jo pričakoval. Vse je enkrat prvič.

sreda, 20. februar 2008

Zakaj mi dela Hibernate tako počasi?

Hibernate je zakon
Zadnje čase se veliko ukvarjam z tehnologijami: Hibernate, Java, ... Zadolžen sem za postavitev okolja, ki bi bilo uporabno ostalim sodelavcem na tem projektu.
Da bi pokazal primere uporabe razvite rešitve, sem sestavil nekaj "uporabniku prijaznih" unit testov (JUnit). Unit teste sem spisal na hitro, ker se mi že malo mudi; prav tako, nisem ravno bil priden programer in nisem pisal toString, equals, hashCode metod v svojih podatkovnih modelih.
Tako sem si vzel včeraj in danes na poti dom/služba; na vlaku; čas, da sem spisal te manjkajoče metode vsaj v abstraktnih razredih - kjer je največ lastnosti. Sem "goreč" zagovornik pisanja teh metod, vsaj tako sem se naučil iz knjig, ki sem jih prebral.
Unit testi so super: lahko jih pišeš neglede na to ali imaš dostop do baze in/ali logika že obstaja: to je ravno sestavi del uporabnosti unit testa: Jaz vem, kaj mora ta metoda vrnit za znan vhod; kako bo to naredila: znajdi se... To je predmet testranja pri unit testu.
In jaz sem priden in konsistenten in pišem vse tako kot je treba.

Ali je to res pravilno?: Ne.
Danes zjutraj me je pričakalo čudovito presenečenje, ki si ga nekaj trenutkov nisem znal razložit. Oči so mi že skoraj zapustile jamice, ko sem občudoval kako počasi mi delujejo moji unit testi - pa tako ponosen sem bil na vse: da sem jih končno sestavil, ves čas: ki sem ga porabil, da sem spisal toString, hashCode in equals metode za vse te številne lastnosti. In kaj dobim: Eclipse se mi je obesil in pokazal bel zaslon... Nevrončki v možganih so začeli brneti kot star katerpiler: vso kolesje se je začelo vrteti in mleti - mleti vse misli od včeraj, danes. Kaj se je spremenilo od včeraj, ko sem nazadnje izvedel unit teste? Hja: dodal si toString, hashCode, equals... Hmmm.

Čudno se mi je zdelo
Čudno se mi je zdelo, zakaj Hibernate ni naredil pri izgradnji modelov teh metod: zakaj sem jih moral pisat sam? Zakaj je naredil te metode samo za kompozitne ID-je? Včeraj pa sem se tudi začel spraševati: je to pametno, da delam toliko dela v teh metodah. Uporabljam Apache Lang paket, ki ima ToStirngBuilder, HashCodeBuilder in EqualsBuilder util razrede, ki so zelo koristni pri gradnji teh metod. A, kaj ko ima posamezen model tudi 15-30 različnih lastnosti. Malo se mi je zdelo sporno: pa to dela hitro? Tolažil sem se, da sem vedno prebral: te metode morajo biti v vsakem modelu - če imaš toString mora biti obvezno tudi equals in hashCode; to je ključnega pomena za HashMap ali HashSet. No pa dobro, bom spisal te metode. Po parih razredih sem izgubil voljo, ker sem štancel te lastnosti in ... mi ni bilo več.
Hkrati sem opazil nekam zelo velik izpis v logih... kaj te to je? Sem sprva mislil, da so spreminjali podatke v bazi: to je stalnica, tako da najprej pomislim na to. Kmalu sem vse potegnil skupaj in 1+1 = ...
Seveda, najprje sem dobil čudne napake: v stilu:
org.hibernate.LazyInitializationException: illegal access to loading collection
Kaj te s tabo je... kaj te to je. Tukaj so prvič začeli nevrončki skakat čez rob. V zadnji knjigi, ki sem jo prebral; je pisalo o "illegal access" napakah v primeru, da druga nit vleti v map-o in spremeni vrednost (doda/odstrani podatek). Ok, kaj ima sedaj s tem? Ni ravno povezano, ali pa tudi: ne vem. A probelem je bil kr hitro jasen: nekdo dostopa do podatkov, ko še ti niso dokončno sestavljeni - to je hashCode, equals. aaa. Prvi aaa trenutek.
Ko sem odpravil to napako, se je začelo dolgorajtno izvajanje... izvajanje in izvajanje. Spet nisem vedel, kaj je narobe. Pa daj: danes res ni moj dan al kaj... pa sem že mislil, da je, ko sem videl tako lepo deklino na vlaku in končno se mi je malo nasmejala in rekla zdravo... ne mora biti tako hitro konec tako prijetnega dneva. Razmisli!
Hmm: nekam dosti se izpisuje v log: se ti ne zdi. Aaa (drugič). toString metoda ... Vse te metode sem obtal v komentarje in poskusil srečo ponovno. Ccc ded: sprve je paljotka - ko jegermajster po grlu... seksi.

Raziskava
Pri branju loga se mi je zdelo čudno: kaj se tolko izpisuje. Kmalu sem ugotovil, da se je v toString skliceval na drug model (njegov toString); ta se je na tretjega in tako dalje. Model je tako super, da hitro pride v krog in ... začel se je krog izvajanja toString metod. Podobno je verjetno bilo za equals in hashCode.
Verjetno ne bi bilo napačno, če bi vključil nekaj ključnih lastnosti, a če že Hibernate sam ni generiral teh metod - jih niti jaz ne rabim. Nisem še prebral celotne knjige o Hibernate in ne vem točno, kako se obnaša glede takšnih problemov. Hmm, spomnim se, da kao v Hibernate 3 te metode niso obvezne... toliko bolje zame.
Drug povod, da sem odstranil te metode je bil tudi ta: kako bo on vedel določiti hashCode in equals vseh lastnosti če pa je ravno poanta Hibernate-a in modelov, da vrnejo podatke "on-demand" ala lazy fetch. V teh metodah sem za vse te lastnosti sprožil nepotrebna SQL poizvedovanja... za kakšno celo: jaz sem opazil le negativne vrednosti in tako ne vidim smisla, da bi implementiral toString, equals in hashCode.

Zaključek
V Hibernate-ovih modelih pazi kako implementiraš toStirng, equals, hashCode: ne velja vse enako kot velja za "običajne" Java POJO-te.

nedelja, 13. januar 2008

Skoraj eno leto

Minilo bo že skoraj leto dni, odkar sem nazadnje zapisal prve besede na tem blebetalniku. Ja, mine čas: ni kaj. Vidim, da se uporabniški vmesnik, za vnos vsebine ni prav nič spremenil v tem času. Verjetno je kak razlog za to.
Torej, kaj imam danes za povedat: sedaj sem se zamislil, kaj sem počel to eno leto. Res je hitro minilo. Staramo se.
Danes bi rad pretrgal to veliko verzel objav. Preteklo leto sem bil priden in sodeloval pri dokaj velikem projektu, ker smo razvijali OSS/BSS sistem za potrebe velikega telekomunikacijskega podjetja. Zanimiva izkušnja, veliko sem se naučil in tudi prispeval pri implementaciji produkta, delal sem na implementaciji poslovne logike. Letošnje leto (v bistvu že pozno lani) sem začel s sodelovanjem na Telekom Slovenije, kjer sodelujem pri razvoju informacijskega sistem; ki je nekako sestavljen iz integracije obstoječih komponent in dodajanja novih (zamenjava obstoječih - posodobitev). Sedaj bo že drugi mesec in sem zelo pozitivno presenečen nad projektom: nudi mi veliko možnosti se naučiti novih stvari in pokazati lastno do sedaj osvojeno znanje. Sedaj sem tudi veliko bolj vključen v sam tok projekta, kot pa na prejšnjem projektu; kjer smo bili neke vrste bosanci, ki smo štancali kodo za štanc mašino (če je kdo sedaj razumel, kaj sem hotel povedat).
Tako, to je nekako tudi vse, kar sem mi je "zanimivega" poslovnega zgodilo v preteklem letu oz. od zadnje objave.
Torej: ideja je takšna, da bi na tem mestu zapisal nekaj izkušenj pri programiranju in predstavil svoje poglede na rešitve problemov; kjer so rešitve računalniške aplikacije. Bi pa se rad dotaknil tudi drugih stvari: kot so nameščanje aplikacij in sistemov. Skratka svoj pogled na ta čudovit virtualni svet.

Prijetno branje.

četrtek, 1. februar 2007

Prvo sporočilo

Pozdravljeni!

Premaknil sem spletno stran, na kateri bi vam rad predstavil nekaj svojih idej, katere oblikujem in pretvarjam v realnost. Projekti in načrti, ki se mi pletejo po glavi in jih je potrebno nekako relaizirati; čeprav kot boste videli v nadaljevanju, se pojavi vprašanje: kaj je realno in kaj ni? Ukvarjal se bom z mnogimi vprašanji; enimi bolj zanimivimi, drugimi pa manj.
Mibesis je kratica, ki predstavlja znamko, pod katero se bom pojavljal pri izdelavi svojih projekov. Več informacij, bo mogoče prebrati tudi na spletni strani http://www.mibesis.eu.