l09 the behavioral problem

58
Lecture 09 The Behavioral Problem

Upload: olafur-andri-ragnarsson

Post on 15-Jan-2015

190 views

Category:

Technology


1 download

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

Page 1: L09 The Behavioral Problem

Lecture 09The Behavioral Problem

Page 2: L09 The 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

Page 3: L09 The Behavioral Problem

Agenda Error handling The Behavioral Problem Object-Relational Behavioral Patterns

– Unit of work– Identity Map– Lazy Load

Object-Relational Mapping

Page 4: L09 The Behavioral Problem

Error Handling

Copyright © 2008 Ólafur Andri Ragnarsson

Page 5: L09 The Behavioral Problem

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

Page 6: L09 The Behavioral Problem

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?

Page 7: L09 The Behavioral Problem

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

Page 8: L09 The Behavioral Problem

Error Flow

Page 9: L09 The Behavioral Problem

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{ ...

Page 10: L09 The Behavioral Problem

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

Page 11: L09 The Behavioral Problem

Unchecked exceptions

Page 12: L09 The Behavioral Problem

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);}

Page 13: L09 The Behavioral Problem

Example

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

}

Page 14: L09 The Behavioral Problem

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);}

Page 15: L09 The Behavioral Problem

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

Page 16: L09 The Behavioral Problem

The Behavioral Problem

Page 17: L09 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?

Page 18: L09 The Behavioral Problem

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?

Page 19: L09 The Behavioral Problem

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

Page 20: L09 The Behavioral Problem

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

Page 21: L09 The Behavioral Problem

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

Page 22: L09 The Behavioral Problem

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?

Page 23: L09 The Behavioral Problem

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

Page 24: L09 The Behavioral Problem

Unit of Work Caller Registration

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

Page 25: L09 The Behavioral Problem

Unit of Work Object Registration

– The object must register itself with the Unit of work

Page 26: L09 The Behavioral Problem

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

Page 27: L09 The Behavioral Problem

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

Page 28: L09 The Behavioral Problem

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)

Page 29: L09 The Behavioral Problem

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

Page 30: L09 The Behavioral Problem

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

Page 31: L09 The Behavioral Problem

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

Page 32: L09 The Behavioral Problem

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

Page 33: L09 The Behavioral Problem

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; }

Page 34: L09 The Behavioral Problem

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(); }

Page 35: L09 The Behavioral Problem

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; }

Page 36: L09 The Behavioral Problem

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); }

Page 37: L09 The Behavioral Problem

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

Page 38: L09 The Behavioral Problem

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

Page 39: L09 The Behavioral Problem

Object Relational Mapping

Page 40: L09 The Behavioral Problem

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

Page 41: L09 The Behavioral Problem

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

Page 42: L09 The Behavioral Problem

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

Page 43: L09 The Behavioral Problem

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

Page 44: L09 The Behavioral Problem

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

Page 45: L09 The Behavioral Problem

Hibernate

Page 46: L09 The Behavioral Problem

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

Page 47: L09 The Behavioral Problem

Architecture High-level architecture

Properties file definedata access

Mapping definitionmaps classes to tables

Page 48: L09 The Behavioral Problem

Architecture

Page 49: L09 The Behavioral Problem

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

Page 50: L09 The Behavioral Problem

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>

Page 51: L09 The Behavioral Problem

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();

Page 52: L09 The Behavioral Problem

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

Page 53: L09 The Behavioral Problem

Example NemandiGateway

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

Page 54: L09 The Behavioral Problem

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(); }

Page 55: L09 The Behavioral Problem

Example NemandiData

– findNemandi

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

Page 56: L09 The Behavioral Problem

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; }

Page 57: L09 The Behavioral Problem

Example NemandiData

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

Page 58: L09 The Behavioral Problem

Summary The Behavioral Problem

– When objects are used Object-Relational Behavioral Patterns

– Unit of work– Identity Map– Lazy Load

Object-Relational Mapping