First and Second Level Cache in Hibernate:
If you have used Hibernate in past then you know that one of the
strongest points of the Hibernate framework is caching, which can
drastically improve the performance of Java application’s persistence
layer if configured and used correctly.
Hibernate provides caching at many levels e.g first level cache at Session level, second-level cache at the SessionFactory level, and query cache to cache frequently executed SQL queries.
The first level cache minimizes database access for the same object.
For example, if you call the get() method to access Employee object
with id = 1 from one session, it will go the database and load the
object into memory, but it will also cache the object in the first-level
cache and when you call the get() method again for the same object from the same session, even after doing some updates on the object, it will return the
object from the cache without accessing the database. You can confirm this from Hibernate’s log file by observing how many queries are executed.
This session-level cache greatly improves the performance of Java application
by minimizing database roundtrips and executing less number of queries. For
example, if an object is modified several times within the same transaction,
then Hibernate will only generate one SQL UPDATE statement at the end of the transaction, containing all the modifications.
But, since this cache is associated with the Session object, which is a
short-lived object in Hibernate, as soon as you close the session, all
the information held in the cache is lost. So, if you try to load the
same object using the get() method, Hibernate will go to the database
again and fetch the record.
This poses a significant performance challenge in an application where
multiple sessions are used, but you don’t need to worry. Hibernate provides
another application-level cache, known as second-level cache, which can be
shared among multiple sessions. This means a request for the same object
will not go to the database even if it is executed from multiple sessions,
the provided object is present in the second-level cache.
The second-level cache is maintained at the SessionFactory level,
which is used to open sessions, hence every session is linked to
SessionFactory. This cache is opposite to first level cache which
is by default enabled in Hibernate, this one is by default disabled
and you need to configure the second level cache in Hibernate configuration
file to enable it.
The second-level cache is provided with the help of caching providers
e.g. EhCache and OSCache. If you look at the cache package in Hibernate,
you can see the implementation of Caching related interfaces by these
providers depending upon which cache you want to use, you can configure
them in the Hibernate configuration file.
Once configured, every request for an object will go to the second level
cache if it is not found in the first level cache. It won’t hit the database
without consulting second-level cache, which means improved performance.
It’s very important for a Java and Hibernate developer to know about
Caching in Hibernate. It’s not just important from the Interview point
of view but also from the application development and performance
improvement point of view.
You will often face performance-related challenges in a real-world
application which contain millions of records, by correctly configuring
Hibernate sessions and writing code which make use of caching, your Java
application can float above water even in the case of a significant load.
Difference between First and Second Level Cache in Hibernate :
Now that we know what is first level and second level cache in Hibernate,
let’s revise some key differences between them from the interview point
The first level cache is associated with Session Object, while the
second-level cache is associated with the SessionFactory object.
This means first level cache’s scope is limited to session-level
while second-level cache’s scope is at the application level.
Since Session object is created on-demand from the SessionFactory
and it’s destroyed once the session is closed, the same query is
run from two different sessions will hit the database twice if
the second-level cache is not configured, On the other hand,
second-level cache remains available throughout the application’s
The first level cache is by default enabled in Hibernate, while
the second level cache is optional. If you need it then you need
to explicitly enable the second level cache on the Hibernate
configuration file i.e. the hibernate.cfg.xml file
You can use the hibernate.cache.provider_class and
hibernate.cache.use_second_level_cache properties to
enable the second level cache in Hibernate. The first
one is the name of the class which implements Second level
cache and could be different, depending upon which cache you
use like EhCache or OSCache.
By default, hibernate.cache.provider_class is set
to org.hibernate.cache.NoCacheProvider class, which
means the second-level cache is disabled. You can enable
it by setting something like org.hibernate.cache.EhCacheProvider
if you want to use EhCache as the second-level cache.
Here is a sample configuration to configure Second level cache with EhCache:
Don’t forget to include hibernate-ehcache.jar
into your classpath, This class comes from that JAR.
The first level cache is available only until the session is open,
once the session is closed, the first level cache is destroyed.
On the other hand, second-level cache is available through the
application’s life-cycle, it is only destroyed and recreated
when you restart your application.
If an entity or object is loaded by calling the get() method then
Hibernate first checked the first level cache, if it doesn’t find
the object then it goes to the second level cache if configured.
If the object is not found then it finally goes to the database
and returns the object, if there is no corresponding row in the
table then it returns null, When an object is loaded from the
database is put on both second level and first-level cache,
so that other session who request the same object can now get
it from the second-level cache, In case if the object is not found
in the first level cache but found in the second level cache because
some other sessions have loaded the object before then it is not only
returned from first level cache but also cached at first level cache,
so that next time if your code request the same object, it should be
returned from 1st level cache rather than going to the 2nd level cache.
Difference between First and Second Level Cache in Hibernate
In general. When an object is pass to save(), update(), or saveOrUpdate() method
and retrieved by load(), get(), list(), iterate(), or scroll() method, that object
is added to the internal cache of the Session and when the flush() is subsequently
called, the state of the object is synchronized with the database.
The second-level cache can also be configured on a per-class
and per-collection basis, which means it can cache a class
or a collection. You can use class-cache and collection-cache
elements in hibernate.cfg.xml to specify which class or collection
to cache at 2nd level cache. You should remember that second-level
cache by default doesn’t cache any entity until you configure it.
You can also use JPA Annotation @Cacheable to specify which
entity is cacheable. and Hibernate annotations @Cache to specify
caching strategy like CacheConcurrencyStrategies like READ_WRITE
or READ_ONLY to tell Hibernate how the second level cache should behave.
That’s all about the difference between first and second level cache in Hibernate.
It’s not just an ORM tool, hibernate is much more than that and in-built caching
is one of the biggest benefits of using Hibernate to implement persistence
of DAO layer in Hibernate. By correctly configuring second-level cache and
writing code to leverage both first level and second level cache in Hibernate,
you can get improved performance in Java application.