Posts Tagged hibernate
Last week I had to review an hibernate powered application due to his poor performance and various instability issues.
In my post Don’t Get Caught Hibernating, I’ve assumed that jdbc connectivity and caching were properly configured.
Well in fact this is not always the case.
Don’t use Hibernate built-in connection pool
Hibernate’s own connection pooling algorithm is, however, quite rudimentary. It is intended to help you get started and is not intended for use in a production system, or even for performance testing. You should use a third party pool for best performance and stability. Just replace the hibernate.connection.pool_size property with connection pool specific settings. This will turn off Hibernate’s internal pool. For example, you might like to use c3p0.
Strangely hibernate log this at info level (not warning) when instantiating the session factory
log.info("Using Hibernate built-in connection pool (not for production use!)");
Instead of using this ‘naive’ implementation, you should configure the session factory to use one of the better javax.sql.DataSource implementation :
- C3P0: add the extra hibernate.c3p0.* properties and that’s it !
- commons-dbcp : perhaps the older implementation, need to adjust the dependencies depending the java version your are using.
- tomcat7-jdbc : simpler implementation than commons-dbcp and contains more features 😉
Note also that other implementations are available.
Don’t forget to
- tune the datasource pool size to fit your production needs
- choose and configure the validation mechanism for opened connections and various strategies testOnBorrow, testWhileIdle,…
- specify the isolation level : it will take the default which is sometimes too high like “repeatable read”
- specify also timeouts, max connection age
- enable preparedStatement cache
As you review your database connection pooling, it may be easy to also instrument it with jamon datasource.
You will gain visibility in your various jdbc accesses. This can also help to identify the ideal pool size (take a look at MaxActive and AvgActive)
Don’t use Hibernate default cache implementation
From hibernate documentation:
Hashtable (not intended for production use) org.hibernate.cache.HashtableCacheProvider memory
The HashtableCacheProvider isn’t a production ready implementation :
- no max size
- no invalidation (lru,…)
- no time to live, time-idle
and can be :
- considered as a memory leak,
- source of OutOfMemoryError,
- out of date data : caches not aware of changes made to the persistent store by another application
As the documentation states, various implementation exists.
From my experience Ehcache is quite easy to setup and ready to scale (cluster).
Don’t forget to disable its phone home mechanism
Hibernate is a great ORM and influenced most of the jpa standardisation. But a lot of his magic power can turn into malediction if you don’t follow some best practices.Some features in the tool are just there to answer ‘yes we can’ but are in my eyes not production ready. After more than 6 years of use on large application development… I could figure it out what works well or not.
Model best practices
- use and abuse of components
- avoid smart getter/setter
- they may break lazy loading or batch-size mechanism (for eg parent-child relationship, firepropertyChange) or trigger undesired update (trim or rounding)
- if you really need them switch to access=”field”
- Use custom usertypes for example to trim/uppercase/unaccent automatically, convert db date types to jodatime equivalent
- implements wisely hashCode and equals(and follow the contract)
- the db id is can be null
- use getter/setter (proxy issues)
- don’t use reflection
- prefer hashCode/EqualsBuilder
- avoid depending on other entities (breaks lazy loading)
- avoid inheritence, prefer composition
- polymorphism and the different hierachy strategies are awesome… but they will bite you one day or another (performance, or “impossibility” to change “type”)
- prefer a cluster safe id generation like identity column or similar (sequence)
Fetch mode, hibernate mappings
- the default should lazy=true in mapping and initialize by navigation or using query fetchmode in your DAO
- avoid lazy=false like the pest, once they are in… it’s hard to get them out !
- Avoid Select N plus 1 :
- one of the plague in most application I’ve seen not only for hibernate powered application (rails,raw jdbc)
- with 2 attributes batch-size at class and collection level you can gain in performance and stability
- join isn’t always the better option (cartesian product, db engine aren’t always good at it).
- Too much data loaded : sometimes it’s better to use hibernate projections or named queries
- Avoid not-found=”ignore”
- ignore not-found on manyToOne relationship force hibernate to check if the records exists… and breaks any lazy load mechanism
- “many-to-zero or one” can be re-implemented by a set for one-to-many
Hibernate query api
- prefer load/get/DetachedCriteria over other hibernate query apis !
- avoid direct sql, prefer externalized named-query for advanced sql query, stored proc calls or legacy table mapping
- avoid “dynamic” hql : concatenation issues (should I close the parenthesis, append “end”, risk of non prepared statement)
some features are available…. but use them wisely, or don’t use them 😉
- Avoid Property-ref : they force hibernate to lookup the database… even if you know that it’s an alternate key
- Avoid Caching ever changing query/entities:
- cache your metamodel (postal code,…)
- Don’t use Hibernate default cache implementation
- be carefull with temporal queries : give me the TVA% at this date: it’s perhaps smarter to do give me all tva indexation events and will find it through java iteration.
- Avoid Composite key
- use them only for legacy table mappings and be aware that the performance won’t be good for example when doing batch loading
In the end it’s a db under the hood
- display the sql logs in development mode(it will show you the effect of one click in your ui)
- sessionfactory settings
- log4j : org.hibernate.SQL
- use jamon (http://jamonapi.sourceforge.net/) to measure first (in production also !)
- don’t return 100000 records to your user : use paging !
- Avoid casting in SQL:
- preserve sql types for exampl 0 vs ‘0’ may prevent your sql engine to use the correct index
- Avoid sql with like “ends with” clause
- Avoid duplicating indexes
- Don’t use Hibernate built-in connection pool
Benefits from metadata
Through the session factory metadata you can :
- create a tool to enforce some rules : use identity column for id, don’t use property-ref,…
- impact analysis : who is using this table/stored procedure,…
- you can generate your model documentation with a tool like linguin maps