12 hibernate int&cache

540 views

Published on

Published in: Technology, Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
540
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
18
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

12 hibernate int&cache

  1. 1. Professional Open Source™ Interceptor Event & Batch Processing© JBoss, Inc. 2003, 2004. 07/17/04 1
  2. 2. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 2
  3. 3. Professional Open Source™  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  }© JBoss, Inc. 2003, 2004. 07/17/04 3
  4. 4. Professional Open Source™  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;  }© JBoss, Inc. 2003, 2004. 07/17/04 4
  5. 5. Professional Open Source™  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;  }© JBoss, Inc. 2003, 2004. 07/17/04 5
  6. 6. Professional Open Source™  public void postFlush(Iterator entities)  {  System.out.println("Creations: " + creates + ", Updates: " + updates); }  public void preFlush(Iterator entities) {  updates=0;  creates=0;  }  ...  }© JBoss, Inc. 2003, 2004. 07/17/04 6
  7. 7. Professional Open Source™  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() );© JBoss, Inc. 2003, 2004. 07/17/04 7
  8. 8. Professional Open Source™ Event system© JBoss, Inc. 2003, 2004. 07/17/04 8
  9. 9. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 9
  10. 10. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 10
  11. 11. Professional Open Source™  Heres 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);  }  }© JBoss, Inc. 2003, 2004. 07/17/04 11
  12. 12. Professional Open Source™  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() );© JBoss, Inc. 2003, 2004. 07/17/04 12
  13. 13. Professional Open Source™  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"/>© JBoss, Inc. 2003, 2004. 07/17/04 13
  14. 14. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 14
  15. 15. Professional Open Source™  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. Thats because Hibernate caches all the newly inserted Customer instances in the session- level cache.© JBoss, Inc. 2003, 2004. 07/17/04 15
  16. 16. Professional Open Source™  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();  }  }© JBoss, Inc. 2003, 2004. 07/17/04 16
  17. 17. Professional Open Source™  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();© JBoss, Inc. 2003, 2004. 07/17/04 17
  18. 18. Professional Open Source™  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();© JBoss, Inc. 2003, 2004. 07/17/04 18
  19. 19. Professional Open Source™  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();© JBoss, Inc. 2003, 2004. 07/17/04 19
  20. 20. Professional Open Source™ PERFORMANCE© JBoss, Inc. 2003, 2004. 07/17/04 20
  21. 21. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 21
  22. 22. Professional Open Source™  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 doesnt make a difference if you use long or java.lang.Long; primitives might be syntactically easier to handle though.© JBoss, Inc. 2003, 2004. 07/17/04 22
  23. 23. Professional Open Source™  Place each class mapping in its own file.  Dont 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.© JBoss, Inc. 2003, 2004. 07/17/04 23
  24. 24. Professional Open Source™  Load mappings as resources.  Deploy the mappings along with the classes they map.© JBoss, Inc. 2003, 2004. 07/17/04 24
  25. 25. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 25
  26. 26. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 26
  27. 27. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 27
  28. 28. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 28
  29. 29. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 29
  30. 30. Professional Open Source™  Dont 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.© JBoss, Inc. 2003, 2004. 07/17/04 30
  31. 31. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 31
  32. 32. Professional Open Source™  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!)© JBoss, Inc. 2003, 2004. 07/17/04 32
  33. 33. Professional Open Source™  Dont 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.© JBoss, Inc. 2003, 2004. 07/17/04 33
  34. 34. Professional Open Source™  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.© JBoss, Inc. 2003, 2004. 07/17/04 34
  35. 35. Professional Open Source™© JBoss, Inc. 2003, 2004. 07/17/04 35
  36. 36. Professional Open Source™  The EntityManager/Hibernate Session is the first-level cache  – always enabled, cant 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)© JBoss, Inc. 2003, 2004. 07/17/04 36
  37. 37. Professional Open Source™  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).© JBoss, Inc. 2003, 2004. 07/17/04 37
  38. 38. Professional Open Source™  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© JBoss, Inc. 2003, 2004. 07/17/04 38
  39. 39. Professional Open Source™  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© JBoss, Inc. 2003, 2004. 07/17/04 39
  40. 40. Professional Open Source™  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!© JBoss, Inc. 2003, 2004. 07/17/04 40
  41. 41. Professional Open Source™Cache compatibility matrix© JBoss, Inc. 2003, 2004. 07/17/04 41
  42. 42. Professional Open Source™  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>© JBoss, Inc. 2003, 2004. 07/17/04 42
  43. 43. Professional Open Source™  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>© JBoss, Inc. 2003, 2004. 07/17/04 43
  44. 44. Professional Open Source™  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>© JBoss, Inc. 2003, 2004. 07/17/04 44
  45. 45. Professional Open Source™  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>© JBoss, Inc. 2003, 2004. 07/17/04 45
  46. 46. Professional Open Source™  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>© JBoss, Inc. 2003, 2004. 07/17/04 46
  47. 47. Professional Open Source™  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();  }  }© JBoss, Inc. 2003, 2004. 07/17/04 47

×