640 likes | 1.01k Views
DESIGNING A PERSISTENCE FRAMEWORK WITH PATTERNS. The Problem: Persistent Objects. persistent object An object that can survive the process or thread that created it. A persistent object exists until it is explicitly deleted ProductDescription Storage Mechanisms and Persistent Objects
E N D
The Problem: Persistent Objects • persistent object • An object that can survive the process or thread that created it. A persistent object exists until it is explicitly deleted • ProductDescription • Storage Mechanisms and Persistent Objects • Object databases • Relational databases • others
The Solution: A Persistence Service from a Persistence Framework • The framework should provide functions such as: • store and retrieve objects in a persistent storage mechanism • commit and rollback transactions
persistence framework • general-purpose, reusable, and extendable set of types that provides functionality to support persistent objects • framework • A set of collaborating abstract and concrete classes that may be used as a template to solve a related family of problems. It is usually extended via subclassing for application-specific behavior
Key Ideas • Mapping • Object identity • Database mapper • Materialization and dematerialization • Caches • Transaction state of object • Transaction operations • Lazy materialization • Virtual proxies
The Representing Objects as Tables pattern • How do you map an object to a record or relational database schema? • The Representing Objects as Tables pattern
aggregate signifies a referential constraint : a ProductDescription row can ' t exist without a related Manufacturer row «Table» «Table» ProductDescription Manufacturer * 1 «PK» OID : char ( 16 ) «PK» OID : char ( 16 ) Description : varchar ( 100 ) Name : varchar ( 100 ) ... City : varchar ( 50 ) PK - primary key «FK» Manu _ OID : char ( 16 ) FK - foreign key UML Data Modeling Profile
Mapping Objects: Database Mapper or Database Broker Pattern • Who should be responsible for materialization and dematerialization of objects (for example, a ProductDescription) from a persistent store?
The PersistenceFacade—as true of all facades—does not do the work itself, but delegates requests to subsystem objects. • direct mapping • persistent object class itself • indirect mapping • Database Broker pattern • Database Mapper pattern
Metadata-Based Mappers • class PersistenceFacade • { • / / . . . • public Object get( OID oid, Class persistenceClass ) • { • // an IMapper is keyed by the Class of the persistent object IMapper mapper = (IMapper) mappers.get( persistenceClass ); • // delegate • return mapper.get( oid ); • } • //... • } • usage: (Manufacturer) PersistenceFacade.getInstance(). get( manuOID, Manufacturer.class) );
UML notation : This is a qualified assocation . It means : 1 . There is a 1 - M association from PersistenceFacade to IMapper objects . 2 . With a key of type Class , an IMapper is found ( e . g . , via a HashMap lookup ) 1 PersistenceFacade «interface» IMapper 1 Class getInstance () : PersistenceFacade get ( OID ) : Object put ( OID , Object ) get ( OID , Class ) : Object ... put ( OID , Object ) ... ProductSpecification ProductSpecification Manufacturer RDBMapper FlatFileMapper RDBMapper note that the Class as a parameter is no longer ... ... ... needed in this version of get , as the class is get ( OID ) : Object get ( OID ) : Object get ( OID ) : Object " hardwired " for a particular put ( OID , Object ) put ( OID , Object ) put ( OID , Object ) persistent type ... ... ... each mapper gets and puts objects in its own unique way , depending on the kind of data store and format
Framework Design with the Template Method Pattern • if (object in cache) • return it • else • create the object from its representation in storage • save object in cache • return it
«interface» IMapper get ( OID ) : Object put ( OID , Object ) ... // template method public final Object get ( OID oid ) { obj := cachedObjects . get ( oid ) ; if ( obj == null ) Abstract { PersistenceMapper // hook method obj = getObjectFromStorage ( oid ) ; TEMPLATE + get ( OID ) : Object { leaf } cachedObjects . put ( oid , obj ) ; } # getObjectFromStorage ( OID ) : Object { abstract } return obj ; ... HOOK }
Further factoring out the varying and unvarying parts of the algorithm.
NextGen Persistence ProductDescription ProductDescription RDBMapper FileWithXMLMapper + ProductDescriptionRDBMapper ( tableName ) # getObjectFromStorage ( OID ) : Object # getObjectFromRecord ( OID , DBRecord ) : Object Sale ProductDescription RDBMapper InMemoryTestDataMapper ... # getObjectFromStorage ( OID ) : Object # getObjectFromRecord ( OID , DBRecord ) : Object Persistence 1 «interface» + PersistenceFacade IMapper 1 getInstance () : PersistenceFacade Class get ( OID ) : Object put ( OID , Object ) get ( OID , Class ) : Object ... put ( OID , Object ) ... Abstract Abstract RDBMapper PersistenceMapper + AbstractRDBMapper ( tableName ) + get ( OID ) : Object { leaf } # getObjectFromStorage ( OID ) : Object { leaf } # getObjectFromStorage ( OID ) : Object # getObjectFromRecord ( OID , DBRecord ) : Object ... - getDBRecord ( OID ) : DBRecord
Configuring Mappers • class MapperFactory • { • public IMapper getProductSpecificationMapper(){...} • public IMapper getSaleMapper() {...} • }
class MapperFactory{ • public Map getAllMappers( ) {...} • } • class PersistenceFacade{ • private java.util.Map mappers = • MapperFactory.getlnstance( ).getAllMappers( ); • }
class ProductSpecificationRDBMapper extends …{ • // hook method override • protected Object getObjectFromStorage( OID oid ) • { • String key = oid.toString(); • dbRec = SQL execution result of: • "Select * from PROD_SPEC where key =" + key • ProductSpecification ps = new ProductSpecification(); • ps.setOID( oid ); • ps.setPrice( dbRec.getColumn("PRICE") ); • ps.setItemID( dbRec.getColumn("ITEM_ID") ); • ps.setDescrip( dbRec.getColumn("DESC") ); • return ps; • } • }
class RDBOperations • { • public ResultSet getProductDescriptionData( OID oid ) {...} • public ResultSet getSaleData( OID oid ) {...} • ... • } • class ProductDescriptionRDBMapper extends AbstractPersistenceMapper{ • protected Object getObjectFromStorage( OID oid ) • { • ResultSet rs = • RDBOperations.getInstance().getProductDescriptionData( oid ); • ProductDescription ps = new ProductDescription(); • ps.setPrice( rs.getDouble( "PRICE" ) ); • ps.setOID( oid ); • return ps; • }
Pattern: Cache Management • to maintain materialized objects in a local cache to improve performance (materialization is relatively slow) and support transaction management operations such as a commit. • When objects are materialized, they are placed in the cache, with their OID as the key. • Subsequent requests to the mapper for an object will cause the mapper to first search the cache, thus avoiding unnecessary materialization
Transactional States and the State Pattern • Persistent objects can be inserted, deleted, or modified. • Operating on a persistent object (for example, modifying it) does not cause an immediate database update; rather, an explicit commit operation must be performed.
[ from DB ] State chart : PersistentObject [ new ( not from DB )] save commit / insert rollback / reload New OldClean OldDirty commit / update delete Legend : delete New -- newly created ; not in DB Old -- retrieved from DB OldDelete Clean -- unmodified rollback / reload Dirty -- modified commit / delete Deleted