Narozdíl od běžných Javovských objektů, které existují v paměti a přetrvávají pouze po dobu běhu aplikace, objekty persistentní jsou navíc uloženy v úložišti objektů, které je spravováno implementací JDO. Je tak nutno řešit problematiku synchronizace persistentních objektů, se kterými se pracuje v aplikaci, s úložištěm objektů. JDO proto zavádí mechanismus transakcí, během kterých se persistentní objekty mohou nacházet v různých stavech, v závislosti na tom, jaký je vztah instance v paměti a v objektovém úložišti.

Transakce

Jak již bylo naznačeno v úvodním článku, veškerá práce s persistentními objekty v JDO probíhá standardně v rámci takzvaných transakcí. Transakce je posloupnost operací s persistentními objekty, u které je vždy zaručeno, že buď proběhne celá (všechny kroky transakce proběhnou úspěšně), nebo neproběhne vůbec, pokud jedna nebo více operací s objektem selže. Tím lze jednoduše dosáhnout toho, že se aplikace vždy nachází v konzistentním stavu, i když některé operace selžou (například vinou ztráty spojení s databázovým serverem).

Veškeré operace s transakcemi implementuje třída javax.jdo.Transaction. Ke každému vytvořenému objektu třídy PersistenceManager, který je typicky vytvářen jeden pro celou aplikaci a poskytuje rozhraní pro řízení persistence objektů, je automaticky vytvořen jeden objekt třídy Transaction, který je přístupný pomocí metody currentTransaction(). Pomocí volání metod tohoto objektu lze řídit průběh transakcí.

Typické použití transakce v JDO si ukážeme na následujícím příkladu. Přitom předpokládáme, že při startu aplikace již proběhla inicializace a nastavení JDO a byl vytvořen objekt PersistenceManager pm.

/* Získáme objekt Transaction */
Transaction tx = pm.currentTransaction();
try
{
    tx.begin();
    /* … operace s persistentnímy objekty … */
    tx.commit();
}
finally
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}

Nová transakce začíná voláním tx.begin(). Pokud všechny operace s persistentními objekty proběhnou správně, ukončí se transakce úspěšně pomocí volání tx.commit() a všechny změny v persistentních datech se promítnou do úložiště objektů. Pokud některá z operací selže, dojde k výjimce a transakce se neukončí. V tom případě dojde k takzvanému anulování transakce (rollback) pomocí volání tx.rollback(), což zajistí, že se všechny objekty vrátí do toho stavu, v jakém se nacházely před začátkem transakce.

Stavy objektů v JDO

Libovolný objekt v Javě, který je schopen persistence (tedy příslušná třída objektů je deklarována v JDO metadatech jako persistentní), se může za běhu aplikace nacházet vždy v některém z několika různých stavů, mezi kterými může přecházet. Tyto stavy reprezentují vztah objektu v běžící aplikaci (v paměti) a úložiště objektů, které je spravováno implementací JDO. Přechod mezi stavy objektu může nastat voláním metod objektu PersistenceManager, který se stará o persistenci všech objektů, změnou stavu probíhající transakce, nebo změnou dat objektu.

Mějme libovolný persistentní objekt p a předem vytvořený objekt správce persistence PersistenceManager pm. Během jakékoli transakce tx může objekt p projít následujícími stavy:

Transient
Objekt vytvořený za běhu aplikace, který nebyl uložen jako persistentní. Takový objekt není ukládán do databáze a JDO se o něj nijak nestará. V tomto stavu se nachází každý nově vytvořený objekt (operátorem new). Persistentní objekt se do tohoto stavu může dostat voláním metody pm.makeTransient() (tato konkrétní instance přestává být svázaná s úložištěm objektů a JDO se o ni dále nestará) nebo voláním pm.deletePersistent(), což způsobí vymazání persistentního objektu z úložiště.
Persistent
Persistentní objekt, neboli objekt ve správě JDO, který je nebo bude uložen do databáze. Podle toho, jaký je vztah dat v instanci objektu a dat uložených v úložišti objektů, se tento stav dělí na několik podstavů.
Hollow
Objekt, který reprezentuje data v úložišti objektů, ale hodnoty těchto dat nejsou součástí objektu v paměti. Persistentní objekt se do tohoto stavu dostane ukončením transakce (volání tx.commit()), kdy se jeho data uloží v úložišti objektů. Dále se v tomto stavu nachází každý objekt nově načtený z úložiště. Přečtením nebo změnou dat objektu dojde k načtení těchto dat z úložiště do instance v paměti a objekt tím přechází do stavu persistent.

Při čtení nebo změně dat objektu nastává přechod do stavu persistent a po úspěšném ukončení transakce se objekt buď navrací do stavu hollow nebo přechází do stavu transient, pokud byl vymazán nebo vyjmut ze správy JDO. V případě anulování transakce (rollback) se všechny objekty vrací do stavu, ve kterém se nacházely na začátku transakce. Stav persistent se dělí na následující podstavy:

Persistent New
Nově vytvořený objekt, který přešel do stavu persistent voláním tx.makePersistent(). Tento objekt dosud není uložen v úložišti, ale bude uložen v okamžiku ukončení transakce.
Persistent Clean
Objekt je uložen v úložišti a data objektu v paměti odpovídají datům v úložišti. Do tohoto stavu objekt přejde ze stavu hollow při prvním pokusu o čtení jeho dat.
Persistent Dirty
Objekt je uložen v úložišti, ale data instance v paměti neodpovídají datům v úložišti. Do tohoto stavu se objekt dostane libovolnou změnou svých dat (změnou hodnoty některé datové položky). Při ukončení transakce se aktuální data zapíší do úložiště.
Persistent Deleted
Objekt je uložen a bylo provedeno volání pm.deletePersistent(). V okamžiku ukončení transakce je objekt vymazán z úložiště a přechází do stavu transient.
Persistent New Deleted
Nepříliš častý případ, kdy byl vytvořen nový persistentní objekt (čímž se dostal do stavu persistent new) a ještě před ukončením transakce byl opět vymazán voláním pm.deletePersistent(). Tento objekt nebude při ukončení transakce vůbec ukládán, ani nikdy uložen nebyl.

Ukažme si nyní změny stavů objektu hypotetické třídy Osoba, která již byla použita v předchozích článcích, v některých typických situacích.

Vytvoření nového persistentního objektu

Vytvoření nového persistentního objektu obvykle probíhá následujícím způsobem:

Transaction tx = pm.currentTransaction();
try
{
    tx.begin();
    Osoba osoba = new Osoba(„Eric“, „Clapton“, 55);
    pm.makePersistent(osoba);
    tx.commit();
}
finally
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}

Stav objektu osoba v průběhu transakce vyjadřuje následující obrázek:

Stavy při vytváření nového objektu

Změna dat objektu

Předpokládejme, že objekt osoba již je vytvořen a je v paměti. Zkusme přečíst některou jeho položku a následně změnit její obsah. Předpokládejme, že existují metody getJmeno() a setJmeno(), které čtou, respektive nastavují obsah položky jmeno.

Transaction tx = pm.currentTransaction();
try
{
    tx.begin();
    String starejmeno = osoba.getJmeno();
    osoba.setJmeno(„Adéla“);
    tx.commit();
}
finally
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}

V tomto případě se budou stavy objektu měnit následujícím způsobem:

Stavy při změně dat objektu

Smazání objektu

Posledním případem je mazání objektu. V nejjednodušším případě mažeme objekt, který se nachází ve stavu hollow. Typická je samozřejmě kombinace s předchozím případem, tedy nejprve přečteme data objektu a poté objekt smažeme.

Transaction tx = pm.currentTransaction();
try
{
    tx.begin();
    String jmeno = osoba.getJmeno();
    pm.deletePersistent(osoba);
    tx.commit();
}
finally
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}

V tomto případě přečtením dat dostaneme objekt do stavu persistent clean a poté jeho smazáním do stavu persistent deleted a ukončením transakce do stavu transient.

Stavy při mazání objektu

V praxi samozřejmě dochází k různým kombinacím popsaných operací a objekt proto může v rámci jedné transakce vystřídat větší množství různých stavů podle výše popsaných pravidel.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět