47
Professional Open Source™ © JBoss, Inc. 2003, 2004. 1 07/17/04 Interceptor Event & Batch Processing

12 hibernate int&cache

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 1

07/17/04

InterceptorEvent & Batch Processing

Page 2: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 2

07/17/04

Interceptors

The Interceptor interface provides callbacks from the session to the application allowing the application to inspect and/or manipulate properties of a persistent object before it is saved, updated, deleted or loaded.

One possible use for this is to track auditing information.

For example, the following Interceptor automatically sets the createTimestamp when an Auditable is created and updates the lastUpdateTimestamp property when an Auditable is updated.

Page 3: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 3

07/17/04

package org.hibernate.test; import java.io.Serializable; import java.util.Date; import java.util.Iterator; import org.hibernate.Interceptor; import org.hibernate.type.Type;

public class AuditInterceptor implements Interceptor, Serializable { private int updates; private int creates;

public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { // do nothing }

Page 4: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 4

07/17/04

public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,Object[] previousState, String[] propertyNames, Type[] types)

{ if ( entity instanceof Auditable ) { updates++; for ( int i=0; i < propertyNames.length; i++ ) { if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) { currentState[i] = new Date(); return true; } } } return false; }

Page 5: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 5

07/17/04

public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { return false; }

public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { if ( entity instanceof Auditable ) { creates++; for ( int i=0; i<propertyNames.length; i++ ) { if ( "createTimestamp".equals( propertyNames[i] ) ) { state[i] = new Date(); return true; } } } return false; }

Page 6: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 6

07/17/04

public void postFlush(Iterator entities) { System.out.println("Creations: " + creates + ", Updates: " + updates); }

public void preFlush(Iterator entities) { updates=0; creates=0; } ... }

Page 7: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 7

07/17/04

The interceptor would be specified when a session is created.

Session session = sf.openSession( new AuditInterceptor() );

You may also set an interceptor on a global level, using the Configuration:

new Configuration().setInterceptor( new AuditInterceptor() );

Page 8: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 8

07/17/04

Event system

Page 9: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 9

07/17/04

If you have to react to particular events in your persistence layer, you may also use the Hibernate3 event architecture.

The event system can be used in addition or as a replacement for interceptors.

Essentially all of the methods of the Session interface correlate to an event. You have a LoadEvent, a FlushEvent, etc

When a request is made of one of these methods, the Hibernate Session generates an appropriate event and passes it to the configured event listener for that type.

Page 10: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 10

07/17/04

Out-of-the-box, these listeners implement the same processing in which those methods always resulted.

However, you are free to implement a customization of one of the listener interfaces (i.e., the LoadEvent is processed by the registered implemenation of the LoadEventListener interface), in which case their implementation would be responsible for processing any load() requests made of the Session.

Page 11: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 11

07/17/04

Here's an example of a custom load event listener:

public class MyLoadListener extends DefaultLoadEventListener { // this is the single method defined by the LoadEventListener interface public Object onLoad(LoadEvent event, LoadEventListener.LoadType loadType) throws HibernateException { if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) { throw MySecurityException("Unauthorized access"); } return super.onLoad(event, loadType); } }

Page 12: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 12

07/17/04

You also need a configuration entry telling Hibernate to use the listener instead of the default listener:

<hibernate-configuration> <session-factory> ... <listener type="load" class="MyLoadListener"/> </session-factory> </hibernate-configuration>

Instead, you may register it programmatically: Configuration cfg = new Configuration(); cfg.getSessionEventListenerConfig().setLoadEventListener( new MyLoadListener()

);

Page 13: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 13

07/17/04

Hibernate declarative security

Usually, declarative security in Hibernate applications is managed in a session facade layer. Now, Hibernate3 allows certain actions to be permissioned via JACC, and authorized via JAAS.

This is optional functionality built on top of the event architecture.

First, you must configure the appropriate event listeners, to enable the use of JAAS authorization.

<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/> <listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/> <listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/> <listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>

Page 14: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 14

07/17/04

Next, still in hibernate.cfg.xml, bind the permissions to roles:

<grant role="admin" entity-name="User" actions="insert,update,read"/> <grant role="su" entity-name="User" actions="*"/>

The role names are the roles understood by your JACC provider.

Page 15: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 15

07/17/04

Batch processing

A naive approach to inserting 100 000 rows in the database using Hibernate might look like this:

Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); for ( int i=0; i<100000; i++ ) { Customer customer = new Customer(.....); session.save(customer); } tx.commit(); session.close();

This would fall over with an OutOfMemoryException somewhere around the 50 000th row. That's because Hibernate caches all the newly inserted Customer instances in the session-level cache.

Page 16: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 16

07/17/04

Batch inserts

When making new objects persistent, you must flush() and then clear() the session regularly, to control the size of the first-level cache.

Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); for ( int i=0; i<100000; i++ ) { Customer customer = new Customer(.....); session.save(customer); if ( i % 20 == 0 ) { //20, same as the JDBC batch size //flush a batch of inserts and release memory: session.flush(); session.clear(); } }

Page 17: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 17

07/17/04

Batch updates

For retrieving and updating data the same ideas apply. In addition, you need to use scroll() to take advantage of server-side cursors for queries that return many rows of data.

Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction();

Page 18: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 18

07/17/04

ScrollableResults customers = session.getNamedQuery("GetCustomers") .setCacheMode(CacheMode.IGNORE) .scroll(ScrollMode.FORWARD_ONLY); int count=0; while ( customers.next() ) { Customer customer = (Customer) customers.get(0); customer.updateStuff(...);

if ( ++count % 20 == 0 ) { //flush a batch of updates and release memory: session.flush(); session.clear(); } } tx.commit(); session.close();

Page 19: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 19

07/17/04

ScrollableResults customers = session.getNamedQuery("GetCustomers") .setCacheMode(CacheMode.IGNORE) .scroll(ScrollMode.FORWARD_ONLY); int count=0; while ( customers.next() ) { Customer customer = (Customer) customers.get(0); customer.updateStuff(...);

if ( ++count % 20 == 0 ) { //flush a batch of updates and release memory: session.flush(); session.clear(); } } tx.commit(); session.close();

Page 20: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 20

07/17/04

PERFORMANCE

Page 21: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 21

07/17/04

Write fine-grained classes and map them using <component>.

Use an Address class to encapsulate street, suburb, state, postcode. This encourages code reuse and simplifies refactoring.

Page 22: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 22

07/17/04

Declare identifier properties on persistent classes.

Hibernate makes identifier properties optional. There are all sorts of reasons why you should use them.

We recommend that identifiers be 'synthetic' (generated, with no business meaning). It doesn't make a difference if you use long or java.lang.Long; primitives might be syntactically easier to handle though.

Page 23: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 23

07/17/04

Place each class mapping in its own file.

Don't use a single monolithic mapping document. Map com.eg.Foo in the file com/eg/Foo.hbm.xml.

This makes particularly good sense in a team environment.

Page 24: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 24

07/17/04

Load mappings as resources.

Deploy the mappings along with the classes they map.

Page 25: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 25

07/17/04

Consider externalising query strings.

This is a good practice if your queries call non-ANSI-standard SQL functions. Externalising the query strings to mapping files will make the application more portable.

Page 26: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 26

07/17/04

Use bind variables.

As in JDBC, always replace non-constant values by "?". Never use string manipulation to bind a nonconstant

value in a query! Even better, consider using named parameters in queries.

Page 27: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 27

07/17/04

Understand Session flushing.

From time to time the Session synchronizes its persistent state with the database. Performance will be affected if this process occurs too often.

You may sometimes minimize unnecessary flushing by disabling automatic flushing or even by changing the order of queries and other operations within a particular transaction.

Page 28: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 28

07/17/04

In a three tiered architecture, consider using saveOrUpdate().

When using a servlet / session bean architecture, you could pass persistent objects loaded in the session bean to and from the servlet / JSP layer. Use a new session to service each request. Use Session.update() or Session.saveOrUpdate() to update the persistent state of an object.

Page 29: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 29

07/17/04

In a two tiered architecture, consider using session disconnection.

Database Transactions have to be as short as possible for best scalability. However, it is often neccessary to implement long running Application Transactions, a single unit-of-work from the point of view of a user.

This Application Transaction might span several client requests and response cycles. Either use Detached Objects or, in two tiered architectures, simply disconnect the Hibernate Session from the JDBC connection and reconnect it for each subsequent request. Never use a single Session for more than one Application

Transaction usecase, otherwise, you will run into stale data.

Page 30: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 30

07/17/04

Don't treat exceptions as recoverable.

This is more of a necessary practice than a "best" practice. When an exception occurs, roll back the Transaction and close the Session.

Page 31: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 31

07/17/04

Prefer lazy fetching for associations.

Use eager (outer-join) fetching sparingly. Use proxies and/or lazy collections for most associations to classes that are not cached at the JVM-level. For associations to cached classes, where there is a high probability of a cache hit, explicitly disable eager fetching using outer-join="false".

When an outer-join fetch is appropriate to a particular use case, use a query with a left join.

Page 32: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 32

07/17/04

Consider abstracting your business logic from Hibernate.

Hide (Hibernate) data-access code behind an interface. Combine the DAO and Thread Local Session patterns.

You can even have some classes persisted by handcoded JDBC, associated to Hibernate via a User-Type. (This advice is intended for "sufficiently large" applications; it is not appropriate for an application

with five tables!)

Page 33: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 33

07/17/04

Don't use exotic association mappings.

Good usecases for a real many-to-many associations are rare. Most of the time you need additional information stored in the "link table".

In this case, it is much better to use two one-to-many associations to an intermediate link class.

In fact, we think that most associations are one-to-many and many-to-one, you should be careful when using any other association style and ask yourself if it is really neccessary.

Page 34: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 34

07/17/04

The cache is used whenever – the application performs a lookup by identifier with getReference() or find() – JBoss EJB3/Hibernate resolves an association lazily – (we may also cache queries)

The cache type can be – transaction scope cache – process scope cache – cluster scope cache

The EJB3/Hibernate caching system has several layers, i.e. a cache miss at the transaction level might be followed by a lookup at the process- or cluster level and only then produce a database hit.

Page 35: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 35

07/17/04

Page 36: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 36

07/17/04

The EntityManager/Hibernate Session is the first-level cache

– always enabled, can't be turned off (mandatory for transaction integrity)

“I get an OutOfMemoryException when I load 500 000 objects?”

Solution: – Use Query API to define pagination – Query.setMaxResults – Query.setFirstResult

The session cache is a cache of object instances – the second-level cache is a cache of data only (objects are copied out of and into the second-level cache)

Page 37: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 37

07/17/04

The second-level cache

Process or cluster scope caching

– makes data visible in concurrent transactions – this can cause problems if the ORM instance non-exclusive access to the data – it is expensive to ensure consistency of cache and database, and respect transaction isolation Non-exclusive data access – in clustered applications (use a cluster cache) – with shared legacy data (define cache expiry and transaction isolation)

EJB3/Hibernate will not know when shared data has been updated, but you may implement a trigger notification system (difficult).

Page 38: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 38

07/17/04

Cache candidates

Especially good classes for caching represent – data that is shared between many users – data that changes rarely – non-critical data (i.e. content-management data) – data that is local to the application and not shared

Potentially bad classes for caching are – data that is owned by a particular user – data that is updated often – financial data – data that is shared with legacy applications

Reference data is an excellent candidate for caching with expiry: – a small number of instances (< 1000) – each instance referenced by many other instances – instances are rarely (or never) updated

Page 39: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 39

07/17/04

Hibernate cache concurrency strategies

transactional ➔ Available in managed environments (appserver), full isolation up to repeatable read. Use

this strategy for read-mostly data where it is critical to prevent stale data in concurrent transactions, in the rare case of an update.

read-write ➔ Maintains read-commited isolation, only in non-cluster environments, uses a timestamp

mechanism, use it for read-mostly data.

nonstrict-read-write ➔ Makes no guarantee of consistency, uses an expiry timeout.

read-only ➔ Useable for data that never changes, use it for reference data

Page 40: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 40

07/17/04

Hibernate built-in cache providers

EHCache ➔ Default, simple process cache for a single VM, supports query caching.

OpenSymphony OSCache ➔ Single process cache, rich set of expiration options and query caching.

SwarmCache ➔ Cluster-only cache system with invalidation, no query cache support.

JBossCache ➔ Fully transactional replicated cache, supports query caching. Not every Cache Provider can use every Concurrency Strategy!

Page 41: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 41

07/17/04

Cache compatibility matrix

Page 42: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 42

07/17/04

Cache Configuration

To activate second-level caching, you need to define the hibernate.cache.provider_class property in the hibernate.cfg.xml file as follows:

<hibernate-configuration> <session-factory> ... <property name="hibernate.cache.provider_class">

org.hibernate.cache.EHCacheProvider </property> ... </session-factory> </hibernate-configuration>

Page 43: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 43

07/17/04

You can activate second-level caching classes in one of the two following ways:

1. You activate it on a class-by-class basis in the *.hbm.xml file, using the cache attribute:

<hibernate-mapping package="com.wakaleo.articles.caching.businessobjects"> <class name="Country" table="COUNTRY" dynamic-update="true">

<meta attribute="implement-equals">true</meta> <cache usage="read-only"/> ... </class> </hibernate-mapping>

Page 44: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 44

07/17/04

2. You can store all cache information in the hibernate.cfg.xml file, using the class-cache attribute:

<hibernate-configuration> <session-factory> ... <property name="hibernate.cache.provider_class"> org.hibernate.cache.EHCacheProvider

</property> ... <class-cache class="com.wakaleo.articles.caching.businessobjects.Country"

usage="read-only" />

</session-factory> </hibernate-configuration>

Page 45: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 45

07/17/04

Next, you need to configure the cache rules for this class. you can use the following simple EHCache configuration file:

<ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false“ timeToIdleSeconds="120“ timeToLiveSeconds="120" overflowToDisk="true“ diskPersistent="false“ diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <cache name="com.wakaleo.articles.caching.businessobjects.Country"

maxElementsInMemory="300“ eternal="true" overflowToDisk="false" /> </ehcache>

Page 46: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 46

07/17/04

Using Query Caches

In certain cases, it is useful to cache the exact results of a query, not just certain objects.

To do this, you need to set the hibernate.cache.use_query_cache property in the hibernate.cfg.xml file to true, as follows:

<property name="hibernate.cache.use_query_cache">true</property>

Page 47: 12  hibernate int&cache

Professional Open Source™

© JBoss, Inc. 2003, 2004. 47

07/17/04

Then, you use the setCacheable() method as follows on any query you wish to cache:

public class CountryDAO { public List getCountries() { return SessionManager.currentSession() .createQuery("from Country as c order by

c.name") .setCacheable(true) .list(); } }