l09 the behavioral problem

Post on 15-Jan-2015

190 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

The Data Source Layer patterns introduced in lecture L08 are structural patterns. They deal with moving data to and from the database. They try to solve the impedance mismatch problem. However, they do not have any logic as to when and under what circumstances data should be loaded to from the database and when written. Clearly accessing the database is slow, and doing so needlessly hurts performance. In this lecture we look at the behavioural problem. How to solve issues like writing only changed record back into the database, loading only the needed data once, and how to load the data model partially. We introduce three new design patterns: Unit of Work, Identity Map and Lazy Load. Vist the course home page: http://www.olafurandri.com/?page_id=2573

TRANSCRIPT

Lecture 09The Behavioral Problem

Reading Fowler 3 Mapping to Relational Database

– The Behavioural Problem Fowler 12: Object-Relational Behavioral

Patterns– Unit of work– Identity Map– Lazy Load

Agenda Error handling The Behavioral Problem Object-Relational Behavioral Patterns

– Unit of work– Identity Map– Lazy Load

Object-Relational Mapping

Error Handling

Copyright © 2008 Ólafur Andri Ragnarsson

Error handling Important aspect of programming

– Programming the best case is usually easy– Making programs robust is another thing

Empty catch-blocks are usually not acceptable– Can be worse since the error gets lost– system.out.println is usually not practical

How to handle exception– Log the exception– Create a new exception and throw– Ignore and have upper layers handle the exception

Some guidelines If you cannot handle an exception, don’t

catch it If you catch an exception, don’t eat it If you need to handle an exception

– Log with useful information– Catch it where you can do something with it

Use domain specific exception– Removes dependences– Example: Should SQLException be handled in

the web layer if there is duplicate row in the database?

Exception Handling Exceptions flow through layers

– Catch exception at the source and throw a domain specific exception

– Upper layers will handle the error Example: Add User

– Table Data Gateway add method catches a duplicate database exception

– Throw domain specific exception– Each layer will ignore the exception, just pass it through– Web layer decides to display message to user saying the

username chosen is already taken

Error Flow

Types of Exceptions Unchecked

– Can occur at any time– For example

• OutOfMemoryError, NullPointerException Checked

– Part of declaration, must he handled or specifically handed to the caller

public static String readFirstLine(String filename)throwsIOException{ ...

Unexpected Exceptions Problem with checked exceptions

– Too much code – unnessary try-catch blocks– Hard-to-read code – difficult to see the real code– The real error can get lost– Dependencies

Guidelines– Use checked exception if caller must deal with the

problem, the exception has direct consequences to the computation

– In layered systems, if the calling layer will not be able to do anything, log and throw unchecked exception

– Layer controlling the flow will handle

Unchecked exceptions

Examplepublic class UserInserter extends SqlUpdate{ ... public int insert(User user) { int rows = 0; try { rows = update(new Object[] { user.getUsername(), user.getName(), user.getEmail(), user.getPassword(), }); } catch (DataIntegrityViolationException divex) { String msg = "User '" + user.getUsername() + "' is already registered."; log.info(msg); throw new RuDuplicateDataException(msg, divex);}

Example

catch (Throwable t) { String msg = "Unable to access Database: cause: " + t.getMessage(); log.severe(msg); throw new RuDataAccessException(msg, t); } return rows; }

}

UserDataGateway Do not need to handle the exception

public class UserData extends RuData implements UserDataGateway{ UserInserteruserInserter = ...

public void addUser(User user) { userInserter.insert(user); } ...} public interface UserDataGateway extends RuDataGateway

{ User findUser(int id); Collection findByName(String name); void addUser(User user); void updateUser(User user); void deteleUser(int id);}

Which of these statements is not true

A) Checked exceptions must be always be handled by callerB) In layered systems, each layer must handle exceptionsC) Unchecked exceptions are never handledD) Checked exceptions require more coding

QUIZ

The Behavioral Problem

The Behavioral Problem Object-Relational Mapping

– How you relate tables to objects The Data Source Layer patterns are architectural

patterns – the focus on structure– Row Data Gateway, – Table Data Gateway, – Active Record, and – Data Mapper

They simply tell you how to load and save objects to tables– What if you maintain these objects in-memory?

The Behavioral Problem How to get various object to load and save

themselves to the database– With objects in memory, how can we keep

track of modified objects?– What if we have two of the same object in

memory and both are changed?– How can we maintain consistency and data

integrity?– What if you need object that is already in

memory?

Keeping track of changed Objects Simple way is to have an object that keeps

track of other objects– Unit of Work

The idea is this– When object is loaded it is registered as

“clean” in the UoW– If modified, it is marked “dirty”– When writing all objects back, just write the

dirty ones

Keeping track of loaded Objects What if you need an object from the

database – is it already loaded? And changed?– Identity Map

The idea is this– Keep all objects in a map and check get them

from the map– If they are not in the map, load them from the

database

Loading Objects For rich data models, what about loading

object hierarchies?– Do we need to load all linked objects?– Lazy Load

The idea is this– We load part of the objects but maintain a

placeholder that we use when the rest of the object is needed

Unit of WorkMaintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution

of concurrency problems Keeps track of objects that are moved in

and out of the database– What has changed?

Unit of Work How It Works

– Unit of Work is an object that tracks all changes to the database

– As soon as something affects the database, tell the Unit of Work

– The Unit of Work must know the state of objects• Upon committing the Unit of Work decides what to do• Application programmers don’t have know what to write to the

database Two methods

– Caller registration– Object registration

Unit of Work Caller Registration

– User of the object has to remember to register the object with the Unit of Work for changes

Unit of Work Object Registration

– The object must register itself with the Unit of work

Unit of Work When to Use It

– When you have in-memory objects you need to synchronize with the database

– When you have many updates to objects and you want to avoid unneeded calls to the database to save the object

Benefits– Keeps the state of object in one place

Identity MapEnsures that each object gets loaded only

once by keeping every loaded object in a map. Looks up objects using the map

when referring to them Keeps a record of all the objects that have

been read

Identity Map How It Works

– Contains a map of all loaded objects– Provides method to get the objects

Choice of Key– Usually the primary key

Explicit or Generic– Explicit Identity Maps have method of the type of

the object• Person findPerson (1)

– Generic Identity Maps have generic objects and keys• Object find(“person”, 1)

Identity Map How Many

– One map per class or per session– Session maps works for database-unique keys– For multiple maps, maintain one per class or per

table Where to put them

– Identity maps need to be somewhere– Can be part of Unit of work– Can be in a Registry

Identity Maps can be used as cache– Works well if objects are read-only

Identity Map When to Use It

– When you need to load objects to memory and you don’t want them duplicated

– Main benefit of Identity Map is avoiding problems when object is updated in-memory

– For immutable object, such as value object, Identity Map is not needed – object may be duplicated

Performance– When you need caching of objects for

performance

Lazy LoadAn object that doesn’t contain all of the data

you need but knows how to get it Load only the data that is needed

– Load the rest when it is needed

Lazy Load How It Works

– Object can contain other objects and associations

– Loading all the data might be too much– Lazy Load delays loading until the objects are

needed Four ways to implement Lazy Load

– Lazy Initialization – Virtual Proxy– Value Holder– A ghost

Lazy Load Lazy Initialization

– Uses a special marker value (usually null) to indicate a field isn't loaded

– Every access to the field checks the field for the marker value and if unloaded, loads it

Class Supplier...

public List getProducts() { if (products == null) products = Product.findSupplier(getId()); return products; }

Lazy Load Virtual Proxy

– An object with the same interface as the real object

– The first time one of its methods are called it loads the real the object and then delegates. Class VirtualList...

private List source; private VirtualListLoader loader; public VirtualList(VirtualListLoader loader) { this.loader = loader; } private List getSource() { if(source == null) source = loader.load(); return source(); } public int size() { return getSource().size(); }

Lazy Load Value Holder

– An object with a getValue method– Clients call getValue to get the real object, the

first call triggers the loadClass SupplierVH...

private ValueHolder products; public List getProducts() { return (List)products.getValue(); } Class ValueHolder…

private Object Value; ... public Object getValue() { if (value==null) value = loader.load(); return value; }

Lazy Load A ghost

– The real object without any data– The first time you call a method the ghost

loads the full data into its fieldsClass Employee... public String Name { get { Load(); return _name; } set { Load(); _name = value; } } String _name;

class Domain Object

protected void Load() { if(IsGhost()) DataSource.load(this); }

Lazy Load When to Use It

– When you have complex objects with associations with other objects

– Need to decide how much to get on a hit and how many hits we want

– Rule might be to bring in everything you need in one call

• The overhead of taking extra fields in the table is not that high

– The best time to use Lazy Load is when it involves an extra call and the data you’re calling isn’t used when the main object is used

We are writing a business application which is using fairly large data set. We only need to update few objects. Writing them all back to database is too expensive. What pattern can we use?

A) Lazy LoadB) Identity MapC) Unit of WorkD) Data Mapper

QUIZ

Object Relational Mapping

Object Relational Mapping (ORM) Use a mapping layer to map between

objects and tables– Mapping a data representation from an object

model to a relational data model with a SQL-based schema

Mapping requires metadata– XML

Authoring and maintaining metadata is less work than maintaining SQL

Advantages of ORM Can radically reduce the amount of code

you need to write– 30% compared to JDBC for server side

application More Productivity Applications are easier to maintain Fosters thinking about an OO domain

model

Disadvantages of ORM Some loss of control over the persistence

process May be more difficult to tune queries Performance characteristics of the tool

may affect your application’s performance

When to use ORM? Well-suited to ORM

– Read-modify-write lifecycle– Little requirement for stored procedures

Poorly suited to ORM– “Window on data” application– Significant use of stored procedures– Write centric apps, where data is seldom read

When to use ORM? Typical server-side applications are fairly

well suited for ORM– 90%-95% of applications– But there are always some special cases– Mix and match as needed

Hibernate

Hibernate Object/relational mapping tool

– A persistence service that stores Java objects in relational databases

– Provides an object oriented view of existing relational data

Uses reflection and XML mapping files to persist POJOs– No changes to business domain objects– The goal is to relieve the developer from a

significant amount of common data persistence-related programming tasks

Architecture High-level architecture

Properties file definedata access

Mapping definitionmaps classes to tables

Architecture

Database Properties File

– hibernate.properties

Contains information to access the database– Username and password– URL– Database driver

Hibernate will automatically read the file from the classpath

hibernate.connection.username=andrihibernate.connection.password=abc123hibernate.connection.url=jdbc:jtds:sqlserver://honn.ru.is:1433hibernate.connection.driver_class=net.sourceforge.jtds.jdbc.Driver

Mapping File File

– hibernate-mapping– In the same package as Nemandi class

<hibernate-mapping> <class name="org.ru.honn.domain.Nemandi" table="NEMENDUR">

<id name="kennitala" column="kennitala" type="string"> </id>

<property name="nafn" column="nafn" type="string" length="64" not-null="false"/> <property name="netfang" column="netfang" type="string" length="64" not-null="false"/> <property name="hopur" column="hopur" type="string" length="32" not-null="false" /> </class></hibernate-mapping>

Using Hibernate Usually an application will

– Create a single Configuration– Build a single instance of SessionFactory– Then instantiate Session objects

Configuration cfg = new Configuration();cfg.addClass(theClass);SessionFactory factory = cfg.buildSessionFactory();Session session = factory.openSession();

Using Hibernate Configuration

– Allows the application to specify properties and mapping documents to be used when creating a SessionFactor

SessionFactory– Factory class to create Session objects

Session– Interface that represents a transaction– The main function is to offer create, read and

delete operations for instances of mapped entity classes

Example NemandiGateway

public interface NemandiGateway{ public Nemandi findNemandi(String kennitala); public Collection getNemendur(); public void addNemandi(Nemandi nemandi);}

Example NemandiData

– Constructor creates the configuration and the factory

– Variable factory is used when a Session is neededpublic class NemandiData implements NemandiGateway{ SessionFactory factory = null;

public NemandiData() { Configuration cfg = new Configuration(); cfg.addClass(Nemandi.class); factory = cfg.buildSessionFactory(); }

Example NemandiData

– findNemandi

public Nemandi findNemandi(String kennitala){ Session session = factory.openSession(); Nemandi nem = (Nemandi)session.get(Nemandi.class, kennitala); session.close(); return nem;}

Example NemandiData

– getNemendur

– Uses the Hibernate Query Language, HQL

public Collection getNemendur() { Session session = factory.openSession(); List l = session.createQuery( "SELECT n FROM is.ru.honn.domain.Nemandi AS n").list(); session.close(); return l; }

Example NemandiData

– addNemandi public void addNemandi(Nemandi nemandi) { Session session = factory.openSession(); Transaction tx = session.beginTransaction(); session.save(nemandi); tx.commit(); session.close(); }

Summary The Behavioral Problem

– When objects are used Object-Relational Behavioral Patterns

– Unit of work– Identity Map– Lazy Load

Object-Relational Mapping

top related