Ve třetím díle seriálu jsme vytvořili jednoduchou
Java třídu, ke které jsme v díle předchozím vytvořili
zrcadlový obraz – persistentní Caché třídu. Jak
definice Caché třídy vypadá, jsme měli možnost již
vidět, nicméně pro nás v tomto okamžiku není její
znalost podstatná. S Caché totiž nebudeme pracovat
přímo, ale prostřednictvím objektů Javy. A o těchto
objektech si dnes budeme povídat.
Jalapeno poskytuje několik API objektů pro řízení
persistence. Jedním z těchto objektů je aplikační
kontext reprezentovaný třídou ApplicationContext
(com.intersys.pojo.ApplicationContext).
Tato třída implementuje různé možnosti připojení k
databázi a k získání instance nejdůležitější API
třídy – Správce objektů – ObjectManager
(com.intersys.pojo.ObjectManager). Následující krátký
kód ukazuje, jak je možno otevřít spojení s databází
a instancovat ObjectManager.
String url="jdbc:Cache://" + host +
":1972/SYM";
Class.forName
("com.intersys.jdbc.CacheDriver");
Connection connection = DriverManager.getConnection
(url, username, password);
objectManager =
ApplicationContext.createObjectManager (connection);
Mimochodem, z příkladu je zřejmé, že připojení ke
Caché je realizováno JDBC ovladačem. Ovladač Caché je
čistě javovská komponenta, která implementuje jak
relační, tak zároveň i objektový přístup k datům
uloženým v Caché a ke kódu uloženému formou metod v
Caché třídách. Ale o tom opět více v některém
budoucím díle.
Máme-li instancován objekt ObjectManager, můžeme
volat jeho metody pro manipulování s daty na straně
Caché. Například můžeme vložit do databáze nový
záznam pomocí metody insert.
import com.intersystems.objects.*;
...
faktura f = new faktura();
...
Id id = (Id)objectManager.insert(f, true);
Druhý argument metody říká, zda se má provést
„důsledné“ uložení, tedy zda se mají uložit současně
i změny objektů na něž odkazuje právě ukládaný
objekt. V našem příkladu faktura ukazuje na objekty
polozka, tedy určitě budeme chtít spolu s fakturou
uložit i její případné položky. Caché zároveň provede
validaci čísla faktury, dle anotace uvedené u třídy
ucto.faktura:
@Index(name="cislofakturyIndex",
isUnique=true, propertyNames={"cislofaktury"})
Následující tabulka podává stručný přehled o
několika užitečných metodách správce objektů.
Specifikace |
Návratová hodnota |
Popis |
---|---|---|
openById(class,id) |
Object |
Otevírá objekt zadané třídy podle Id v |
openByPrimaryKey(vlase,primaryKey) |
Object |
Otevírá instanci zadané třídy podle |
openByQuery(vlase,sql,args[]) |
java.util.Iterator |
Vrací množinu instancí třídy dle zadané |
attach(object pojo) |
void |
Pokud byl objekt připojen ke Caché kopii |
detach(object pojo) |
object |
Provede odpojení objektu od Caché, tedy od |
Flush |
void |
Synchronizuje persistentní kontext s Caché |
Insert(object pojo,Boolean deep) |
Id |
Vytvoří novou instanci třídy v Caché a |
Save(object pojo,Boolean deep) |
Id |
Vytvoří novou instanci v Caché, nebo |
purgeFromMemory(object pojo) |
void |
Zruší asociaci mezi Java verzí objektu a |
refresh(object pojo) |
void |
Provede aktualizaci java objektu dle |
removeFormDatabase(object pojo,Id id) |
void |
Nalezne odpovídající objet v databázi |
close() |
void |
Uzavře správce objektů a zneplatní jej |
Třída ObjectManager obsahuje též metody pro práci
s transakcemi, které zde nebudeme rozebírat, neboť na
nich není nic objevného a metody pro instancování
dalších objektů Jalapeno API a to jmenovitě Utilities
a ExtentManager.
ExtentManager
Tato Třída poskytuje rozhraní pro práci s oblastmi
databází na úrovni celých persistentních tříd, tedy
nikoliv na úrovni instancí objektů. Její metody lze
použít například pro zrušení definice třídy, smazání
všech instancí třídy najednou, přepočítání indexů
(toto normálně v Caché není třeba, jen pokud
programátor změní definici třídy, je nutno uvést
hodnoty indexů s jejich definicemi) apod. V
neposlední řadě lze použít metodu pro vygenerování
pseudonáhodných instancí tříd; to se hodí zvláště
potřebujeme-li otestovat aplikaci na velkém objemu
dat, která ovšem ne vždy pro testování máme k
dispozici z reálného provozu.
ObjectManagerFactory
Tato třída poskytuje rozhraní pro správu připojení ke
Caché databázi, např. definuje výchozí hodnoty
připojení – url, jméno a heslo a jiná nastavení.
Settings
Tato pomocná třída poskytuje rozhraní pro správu
chování třídy ObjectManager. Asi nejdůležitějšími
metodami jsou getFetchPolicy
a setFetchPolicy
. Správné nastavení politiky
synchronizace Java klienta se stranou Caché má totiž
zásadní vliv na výkon celé aplikace.
Caché podporuje dva typy politik pro synchronizaci a
to FETCH_POLICY_EAGER
a FETCH_POLICY_LAZY
. Pokud zvolíte politiku
EAGER, pak v okamžiku instancování POJO objektu se
automaticky z databáze načtou hodnoty všech
vlastností objektu včetně objektů na něž daný objekt
odkazuje a to do všech pokolení odkazů. Toto může
vést k přenosům velkého objemu dat a v krajním
případě k havárii aplikace z důvodu nedostatku
paměti. V druhém případě, při použití LAZY politiky,
se sice vytvoří instance Java objektu ale hodnoty
vlastností se načítají až na vyžádání, při prvním
odkazu na ně.
Utilities
Tato třída implementuje několik metod pro práci s XML
dokumenty. Zejména jde o metody pro serializaci do
XML a deserializaci z XML do instance POJO objektu.
Nyní si konečně můžeme poskládat celý příklad –
zde je jeho kód:
package ucto;
import java.util.*;
import java.io.*;
public class Main {
public Main()
{
}
public static void main(String[] args) {
String
cisloFaktury;
Random rnd = new Random();
try {
BufferedReader in = new BufferedReader(new
InputStreamReader(System.in));
System.out.println("Číslo faktury:");
cisloFaktury = in.readLine();
faktura f = new faktura();
f.polozky = new ArrayList();
f.cislo_faktury = cisloFaktury;
f.prijemce="Jiri Novy";
f.datum_vystaveni= new Date();
polozka p = new polozka();
p.castka = Float.valueOf(rnd.nextInt(1200));
p.popis = "položka číslo 1";
f.polozky.add(p);
polozka pp = new polozka();
pp.castka = Float.valueOf(rnd.nextInt(1800));
pp.popis = "položka číslo 2";
f.polozky.add(pp);
f.castka = p.castka + pp.castka;
System.out.println("Číslo faktury: " +
f.cislo_faktury);
System.out.println("Částka celkem: " + f.castka);
DBservice db = new DBservice();
db.ulozFakturu(f,true);
// znicime odkaz na fakturu;
f = null;
System.out.println("Uloženo!");
// upravime fakturu po jejim nacteni z databaze -
zmenime prijemce
Iterator faktury =
db.FakturaDleCisla(cisloFaktury);
// vime ze bude jen jedna, pokud vubec
...
if (faktury.hasNext()) {
faktura
fa = (faktura)faktury.next();
System.out.println("původní příjemce: " +
fa.castka);
fa.prijemce = "Moje Firma, s.r.o.";
System.out.println("částka: " + fa.castka);
db.ulozFakturu(fa,false);
}
System.out.println("Stiskni libovolnou klávesu
pro dokončení...");
String input = in.readLine();;
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Servisní třída:
package ucto;
import com.intersys.pojo.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.*;
import com.intersys.objects.*;
public class DBservice {
ObjectManager
objectManager = null;
/** Creates a new instance of DBservice */
public DBservice() throws Exception {
String host
= "localhost";
String username="SYSTEM";
String password="_SYS";
String url="jdbc:Cache://" + host +
":1972/SAMPLES";
Class.forName("com.intersys.jdbc.CacheDriver");
Connection connection = DriverManager.getConnection
(url, username, password);
objectManager =
ApplicationContext.createObjectManager(connection);
}
protected void ulozFakturu(faktura f, Boolean nova)
throws Exception {
Id id =
(nova ? (Id)objectManager.insert(f, true):
(Id)objectManager.save(f, true));
System.out.println("object id: " + id.toString());
}
Iterator FakturaDleCisla(String cisloFaktury) throws
Exception {
String[]
args = {cisloFaktury};
return objectManager.openByQuery(faktura.class,
"cislofaktury = ?", args);
}
}
Zkušený programátor mi snad promine styl, zde mi
jde jen o ukázku a uvedení některých metod API.
Příště nás čeká nová sekce, začneme popisovat
spolupráci Caché a Javy z druhé strany, z prostředí
Caché.