Programování

Perzistence objektů a Java

Trvanlivost objektu, nebo vytrvalost, je termín, který často slyšíte používaný ve spojení s otázkou ukládání objektů v databázích. Očekává se, že persistence bude fungovat s transakční integritou, a proto podléhá přísným podmínkám. (Další informace o zpracování transakcí najdete v části Zdroje v tomto článku.) Naproti tomu jazykové služby nabízené prostřednictvím knihoven a balíčků standardních jazyků často neobsahují transakční omezení.

Jak uvidíme v tomto článku, důkazy naznačují, že jednoduchá persistence prostředí Java bude pravděpodobně pocházet ze samotného jazyka, zatímco sofistikované funkce databáze budou nabízeny prodejci databází.

Žádný objekt není ostrov

Ve skutečném světě zřídka najdete objekt, který postrádá vztahy k ostatním objektům. Objekty jsou součástí objektové modely. Otázka trvanlivosti objektů přesahuje otázku trvanlivosti a distribuce objektových modelů, jakmile provedeme pozorování, že objekty jsou vzájemně propojeny na základě jejich vzájemných vztahů.

Relační přístup k ukládání dat má tendenci agregovat data podle typu. Řádky v tabulce představují fyzický agregát objektů stejného typu na disku. Vztahy mezi objekty jsou pak reprezentovány klíči, které jsou sdíleny napříč mnoha tabulkami. Ačkoli prostřednictvím organizace databáze relační databáze někdy umožňují společné umístění tabulek, které se pravděpodobně použijí společně (nebo seskupený) ve stejné logické oblasti, jako je databázový segment, nemají žádný mechanismus pro ukládání vztahů objektů v databázi. Proto, aby bylo možné vytvořit objektový model, jsou tyto vztahy konstruovány z existujících klíčů za běhu v procesu označovaném jako stůl se připojí. Toto je stejná známá vlastnost volaných relačních databází nezávislost na datech. Téměř všechny varianty objektových databází nabízejí nějaký mechanismus pro zvýšení výkonu systému, který zahrnuje složité objektové vztahy přes tradiční relační databáze.

Dotazovat se nebo navigovat?

Při ukládání objektů na disk se potýkáme s výběrem společného umístění souvisejících objektů, abychom lépe vyhověli navigačnímu přístupu, nebo abychom ukládali objekty do kolekcí podobných tabulkám, které agregují objekty podle typu, aby se usnadnil přístup založený na predikátu (dotazy), nebo obojí . Společné umístění objektů v trvalém úložišti je oblast, kde se relační a objektově orientované databáze velmi liší. Další oblastí zájmu je volba jazyka dotazu. Strukturovaný dotazovací jazyk (SQL) a jeho rozšíření poskytly relačním systémům přístupový mechanismus založený na predikátu. Object Query Language (OQL) je objektová varianta SQL, standardizovaná ODMG, ale podpora tohoto jazyka je v současné době nedostatečná. Polymorfní metody nabízejí bezprecedentní eleganci při konstrukci sémantického dotazu pro kolekci objektů. Představte si například polymorfní chování pro účet volala isInGoodStanding. Může vrátit logickou hodnotu true pro všechny účty v dobrém stavu a jinak false. Nyní si představte eleganci dotazování na sbírku účtů, kde inGoodStanding je implementován odlišně na základě obchodních pravidel pro všechny účty v dobrém stavu. Může to vypadat nějak takto:

setOfGoodCustomers = setOfAccounts.query (account.inGoodStanding ());

I když několik existujících databází objektů dokáže zpracovat takový styl dotazu v C ++ a Smalltalk, je pro ně obtížné to udělat pro větší (řekněme 500+ gigabajtů) kolekce a složitější výrazy dotazů. Několik společností poskytujících relační databáze, například Oracle a Informix, brzy nabídne jinou syntaxi založenou na SQL, aby dosáhlo stejného výsledku.

Perzistence a typ

Milovník objektově orientovaného jazyka by řekl, že vytrvalost a typ jsou ortogonální vlastnosti objektu; to znamená, že trvalé a přechodné objekty stejného typu mohou být identické, protože jedna vlastnost by neměla ovlivňovat druhou. Alternativní pohled tvrdí, že perzistence je chování podporované pouze perzistentními objekty a určité chování se může vztahovat pouze na perzistentní objekty. Druhý přístup vyžaduje metody, které instruují trvalé objekty k ukládání a načítání z trvalého úložiště, zatímco první poskytuje aplikaci bezproblémový pohled na celý objektový model - často rozšířením systému virtuální paměti.

Kanonizace a jazyková nezávislost

Objekty stejného typu v jazyce by měly být uloženy v trvalém úložišti se stejným rozložením bez ohledu na pořadí, ve kterém se jejich rozhraní objevují. Procesy transformace rozložení objektu na tento běžný formát jsou souhrnně označovány jako kanonizace reprezentace objektů. V kompilovaných jazycích se statickým typováním (nikoli Java) by objekty napsané ve stejném jazyce, ale kompilované v různých systémech, měly být v trvalém úložišti identicky zastoupeny.

Rozšíření kanonizace adresuje jazykově nezávislou reprezentaci objektů. Pokud lze objekty reprezentovat jazykově nezávislým způsobem, bude možné, aby různé reprezentace stejného objektu sdílely stejné trvalé úložiště.

Jedním z mechanismů k provedení tohoto úkolu je zavedení další úrovně indirection prostřednictvím rozhraní Definition Language (IDL). Rozhraní databáze objektů lze vytvořit prostřednictvím IDL a odpovídajících datových struktur. Nevýhodou vazeb stylu IDL je dvojí: Za prvé, extra úroveň indirection vždy vyžaduje další úroveň překladu, což má dopad na celkový výkon systému; zadruhé, omezuje použití databázových služeb, které jsou jedinečné pro konkrétní dodavatele a které by mohly být cenné pro vývojáře aplikací.

Podobným mechanismem je podpora objektových služeb prostřednictvím rozšíření SQL. Prodejci relačních databází a menší prodejci objektů / relací jsou zastánci tohoto přístupu; Jak úspěšné budou tyto společnosti při formování rámce pro ukládání objektů, však teprve uvidíme.

Otázkou ale zůstává: Je perzistence objektu součástí chování objektu nebo jde o externí službu nabízenou objektům prostřednictvím samostatných rozhraní? A co sbírky předmětů a metody jejich dotazování? Relační, rozšířené relační a objektové / relační přístupy mají tendenci prosazovat oddělení mezi jazykem, zatímco objektové databáze - a samotný jazyk Java - vidí perzistenci jako vnitřní jazyk.

Nativní perzistence Java prostřednictvím serializace

Serializace objektů je mechanismus specifický pro jazyk Java pro ukládání a načítání objektů Java a primitiv do streamů. Je třeba poznamenat, že ačkoli komerční knihovny třetích stran pro serializaci objektů C ++ existují již nějakou dobu, C ++ nikdy nenabídl nativní mechanismus pro serializaci objektů. Zde je návod, jak použít serializaci prostředí Java:

// Zápis „foo“ do streamu (například do souboru)

// Krok 1. Vytvořte výstupní proud

// tj. vytvořte kbelík pro příjem bajtů

FileOutputStream out = nový FileOutputStream ("fooFile");

// Krok 2. Vytvořte ObjectOutputStream

// tj. vytvořte hadici a vložte její hlavu do kbelíku

ObjectOutputStream os = nový ObjectOutputStream (out)

// Krok 3. Napište řetězec a objekt do streamu

// to znamená nechat proud proudit do kbelíku

os.writeObject ("foo");

os.writeObject (nový Foo ());

// Krok 4. Vypláchněte data na místo určení

os.flush ();

The Writeobject metoda serializuje foo a jeho přechodné uzavření - tedy všechny objekty, na které lze v grafu odkazovat z foo. V rámci streamu existuje pouze jedna kopie serializovaného objektu. Ostatní odkazy na objekty jsou uloženy jako úchyty objektů, aby se ušetřilo místo a zabránilo se cyklickým odkazům. Serializovaný objekt začíná třídou následovanou poli každé třídy v hierarchii dědičnosti.

// Čtení objektu ze streamu

// Krok 1. Vytvořte vstupní proud

FileInputStream in = nový FileInputStream ("fooFile");

// Krok 2. Vytvořte vstupní proud objektu

ObjectInputStream ins = nový ObjectInputStream (in);

// Krok 3. Musím vědět, co čtete

String fooString = (String) ins.readObject ();

Foo foo = (Foo) s.readObject ();

Serializace a zabezpečení objektů

Ve výchozím nastavení serializace zapisuje a čte nestatická a nepřechodná pole ze streamu. Tuto charakteristiku lze použít jako mechanismus zabezpečení deklarováním polí, která nemusí být serializována jako soukromé přechodné. Pokud třída nemusí být vůbec serializována, writeObject a readObject metody by měly být implementovány k hodu NoAccessException.

Perzistence s transakční integritou: Představujeme JDBC

Modeled after X / Open's SQL CLI (Client Level Interface) and Microsoft's ODBC abstractions, Java databázové připojení (JDBC) si klade za cíl poskytnout mechanismus připojení k databázi, který je nezávislý na základním systému správy databáze (DBMS). Aby se staly kompatibilními s JDBC, ovladače je třeba podporovat alespoň základní rozhraní API ANSI SQL-2, které poskytuje prodejcům nástrojů a aplikacím třetích stran dostatečnou flexibilitu pro přístup k databázi.

JDBC je navržen tak, aby byl konzistentní se zbytkem systému Java. Prodejcům se doporučuje, aby psali API, které je silněji typované než ODBC, což poskytuje větší statickou kontrolu typu v době kompilace.

Zde je popis nejdůležitějších rozhraní JDBC:

  • java.sql.Driver.Manager zpracovává načítání ovladačů a poskytuje podporu pro nová připojení k databázi.

  • java.sql.Connection představuje připojení k určité databázi.

  • Prohlášení java.sql funguje jako kontejner pro provádění příkazu SQL na daném připojení.

  • java.sql.ResultSet řídí přístup k sadě výsledků.

Ovladač JDBC můžete implementovat několika způsoby. Nejjednodušší by bylo vytvořit ovladač jako most k ODBC. Tento přístup je nejvhodnější pro nástroje a aplikace, které nevyžadují vysoký výkon. Rozšiřitelnější design by zavedl další úroveň nepřímého přenosu na server DBMS poskytnutím síťového ovladače JDBC, který přistupuje k serveru DBMS prostřednictvím publikovaného protokolu. Nejúčinnější ovladač by však měl přímý přístup k proprietárnímu API DBMS.

Objektové databáze a perzistence Java

Řada probíhajících projektů v tomto odvětví nabízí perzistenci prostředí Java na úrovni objektu. Avšak v době psaní tohoto článku jsou Object Design's PSE (Persistent Storage Engine) a PSE Pro jedinými plně objektově orientovanými databázovými balíčky založenými na Javě (alespoň o kterých vím). V sekci Zdroje najdete další informace o PSE a PSE Pro.

Vývoj prostředí Java vedl k odklonu od tradičního paradigmatu vývoje dodavatelů softwaru, zejména na časové ose vývojového procesu. Například PSE a PSE Pro jsou vyvíjeny v heterogenním prostředí. A protože v procesu vývoje neexistuje krok propojení, vývojáři byli schopni vytvořit různé funkční komponenty nezávisle na sobě, což má za následek lepší a spolehlivější objektově orientovaný kód.

PSE Pro má schopnost obnovit poškozenou databázi z přerušené transakce způsobené selháním systému. Třídy, které jsou zodpovědné za tuto přidanou funkčnost, nejsou ve verzi PSE přítomny. Mezi těmito dvěma produkty neexistují žádné další rozdíly. Tyto produkty nazýváme „dribbleware“ - softwarové verze, které vylepšují jejich funkčnost připojením nových komponent. V ne tak vzdálené budoucnosti by se koncept nákupu velkého monolitického softwaru stal věcí minulosti. Nové obchodní prostředí v kyberprostoru společně s výpočty Java umožňuje uživatelům nakupovat pouze ty části objektového modelu (graf objektu), které potřebují, což vede k kompaktnějším koncovým produktům.

PSE funguje následným zpracováním a anotací souborů třídy poté, co byly vytvořeny vývojářem. Z pohledu PSE jsou třídy v grafu objektů buď trvalé, schopné nebo trvalé. Třídy s trvalou schopností mohou přetrvávat samy, zatímco třídy s trvalým vědomím mohou pracovat s trvalými objekty. Toto rozlišení je nutné, protože vytrvalost nemusí být požadovaným chováním pro určité třídy. Postprocesor souboru třídy provádí následující úpravy tříd: