If you have a bigger application you think about performance and how you can improve it. Caching is one way to do this because it enables fewer queries going to the database. Querying the database is always a performance impact because it is an I/O operation. And I/O operations are much slower than operations using only the applications memory.
Caching works between your application and the database to avoid the number of database hits as often as possible.
Per default, Hibernate uses first-level caching which means it stores entities in the application’s memory (allocated for Hibernate) through the session. It is a mandatory cache which all entities have to pass. This has two benefits: if the entity is accessed often then Hibernate remembers this and if your application needs this entity again it is returned from the session’s cache; the second benefit is if you do multiple updates on an entity Hibernate tries to group these updates together and delay the actual database call to reduce I/O traffic. If you close the session then the objects stored in the first-level cache are destroyed and either saved or updated to the database.
You can extend this caching with an optional second-level cache. The first-level keeps being mandatory and is consulted first always. The second-level cache is used to cache object across sessions. For second-level caching, there are some third-party solutions which can be used with Hibernate. Hibernate provides the org.hibernate.cache. CacheProvider interface which has to be implemented by the provider to make Hibernate handle the cache.
There are some cache providers out in the market but Hibernate wants you to choose only one provider for your whole application.
Let me mention some cache providers:
Out of those mentioned above EHCache is the most popular and widely used.
There are some caching strategies which you have to keep in mind when using a second-level cache:
- Read Only This strategy should be used for persistent objects that will be never updated. It is good for reading and caching application configuration and other static data. This is the simplest strategy with the best performance because there is no overload to check if an entity is updated in the database or not.
- Read-Write This strategy is good for entities which are updated by the application. However, if the data is updated either through the database or other applications, then there is no way Hibernate could tell if there was a change or not and your data might be stale.
- Nonrestricted Read-Write If the application only occasionally updates data and strict transaction isolation is not required, this caching strategy might be appropriate.
- Transactional This caching strategy provides support for fully transactional cache providers such as JBoss TreeCache. Such a cache can only be used in a JTA environment and you must specify transaction.manager_lookup_class.
And do not wonder: EHCache supports all of those four strategies mentioned above so it is a good choice to get started with a second-level cache provider.
Alternatively, to entities, you can store queries in a cache too. However, this query cache works close together with the second-level cache so it is only a way to attend if you utilize a second-level cache.
To use the query cache requires two additional cache regions: one for the cached query results and one for the timestamps when a table was lastly updated.
Using a query cache is only reasonable if you have queries which run often with the same parameters.
To have a positive impact on application performance one step is to use some caching between the database and your application. Hibernate offers a simple in-memory cache called the first-level cache which you do not need to enable or configure because it is mandatory.
However, you can extend this feature with a second-level cache which caches objects across sessions for your application. If you are utilizing a second-level cache you can extend caching entities with caching queries which are called often with the same parameters.