The Hibernate second level cache is a shared cache of entity data that belongs to the EntityManagerFactory and serves every session the application opens. The first level cache belongs to one EntityManager and is gone when that EntityManager closes, so every new request reads the same rows again. With the second level cache, the first session reads a row from the database and stores its values, and later sessions take the values from the cache and skip the SELECT.
We use the second level cache for data that is read often and changes rarely, such as countries and currencies.
The following example turns on JCache with Ehcache 3, marks Country as cacheable and runs the same find() in two sessions.
.property("hibernate.cache.region.factory_class", "jcache")
.property("hibernate.javax.cache.provider", "org.ehcache.jsr107.EhcacheCachingProvider")
@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Country { ... }
emf.getCache().evictAll(); // start with an empty cache
emf.runInTransaction(em -> em.find(Country.class, indiaId)); // select c1_0.id,c1_0.capital,c1_0.name from Country c1_0 where c1_0.id=?
emf.runInTransaction(em -> em.find(Country.class, indiaId)); // no SQL: read from the second level cache
Notice that only the first session runs the SELECT, and the second session gets India from the second level cache.
Next, we look at the lookup order and at what the cache stores. After that, we build an Ehcache 3 example that covers concurrency strategies, statistics, collections, query results and eviction.
1. How Does the Hibernate Second Level Cache Work?
Hibernate has two cache levels. The first level is the persistence context of one session, and it is always on. The second level is optional. It sits between all sessions and the database, and a cache library outside Hibernate (the provider) holds the data. For example, a travel booking app shows a country list with currencies on every search page, and without the second level cache, each request reads the same countries from the database again.
| First level cache | Second level cache | |
|---|---|---|
| Belongs to | One EntityManager (session) | The EntityManagerFactory, shared by all sessions |
| Enabled | Always | After we add a provider and mark the entities |
| Holds | Managed Java objects | Column values of each entity (dehydrated state) |
| Lives until | The session closes or clear() runs | Eviction, expiry (time to live) or factory close |
| Two lookups return | The same object | A new object in each session |
| Implemented by | Hibernate | A JCache provider (Ehcache 3, Caffeine) or Infinispan |
Inside the provider, the data is split into regions. A region is a named cache that Hibernate creates for each cached entity class and each cached collection. The Country entity goes into the region com.howtodoinjava.hibernate.secondlevelcache.Country, and its currencies collection into …Country.currencies. Each region can have its own size limit and time to live.
1.1. The Lookup Order Across Two Sessions
When we call em.find(), Hibernate checks three places in a fixed order and stops at the first one that has the entity.
- The first level cache of the current session. If the entity is there, Hibernate returns the same Java object.
- The second level cache region of the entity. On a hit, Hibernate builds a new object from the cached values and adds it to the session.
- The database. Hibernate runs the SELECT, stores the values in the second level cache and the object in the session.
![Sequence diagram with four lifelines: our code, the first level cache, the second level cache and the database. In session 1, em.find(Country, 1) misses the first level cache, misses the second level cache, runs select ... where id=?, puts [New Delhi, 1, India] into the second level cache and returns India. In session 2, the same find misses the first level cache, hits the second level cache and returns India without SQL](https://howtodoinjava.com/wp-content/uploads/2026/10/hibernate-how-hibernate-second-sequence-diagram-four-lifelines-our.png)
1.2. What the Cache Stores
Hibernate does not put our Country objects into the cache. It stores the dehydrated state, which is an array with the property values of the entity, under a key made of the entity name and the id. The example project prints the raw entries for India.
com.howtodoinjava.hibernate.secondlevelcache.Country#1 -> CacheEntry [New Delhi, 1, India]
com.howtodoinjava.hibernate.secondlevelcache.Country.currencies#1 -> CollectionCacheEntry [1]
com.howtodoinjava.hibernate.secondlevelcache.Currency#1 -> CacheEntry [Rupee]
The Country entry holds the capital, the key of the currencies collection and the name. The collection entry holds only the ids of the currencies, and each currency has its own entry in its own region.

Because only values are stored, every hit gives the session a new Country object, and a cached collection is useful only when its element entity is cached too. Otherwise Hibernate gets the ids from the cache and still loads each element from the database.
2. Second Level Cache Example
Our example keeps country and currency reference data. India uses the Rupee and Japan the Yen, whereas Germany and France share the Euro. The example runs on Java 25, Hibernate 7.4.11.Final, Ehcache 3.12.0 and an in-memory H2 database. The complete project on GitHub prints the SQL and the cache statistics of every step and checks them with 22 JUnit tests (mvn -q compile exec:java, mvn test).
2.1. Adding a JCache Provider
Hibernate does not cache the data itself. JCache (JSR-107) is the standard Java caching API, and the hibernate-jcache module connects Hibernate to any JCache provider. We use Ehcache 3 with the jakarta classifier, which is the build for Jakarta EE packages.
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jcache</artifactId>
<version>7.4.11.Final</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.12.0</version>
<classifier>jakarta</classifier>
<exclusions>
<exclusion>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</exclusion>
</exclusions>
</dependency>
The exclusion removes the old JAXB 2 runtime that the Ehcache POM declares. Hibernate 7 already brings JAXB 4 (jaxb-runtime 4.0.7), which Ehcache uses to read ehcache.xml.
2.2. Enabling the Second Level Cache
The cache is off until we name a region factory. Setting hibernate.cache.region.factory_class turns the second level cache on; hibernate.cache.use_second_level_cache defaults to true as soon as a real region factory is configured. We bootstrap with HibernatePersistenceConfiguration.
new HibernatePersistenceConfiguration("second-level-cache")
.managedClasses(Country.class, Currency.class)
.property("hibernate.cache.region.factory_class", "jcache")
.property("hibernate.javax.cache.provider", "org.ehcache.jsr107.EhcacheCachingProvider")
.property("hibernate.javax.cache.uri", "ehcache.xml")
.property("hibernate.cache.use_query_cache", true)
.property("hibernate.generate_statistics", true)
...
Each property in Database.java sets one part of the cache setup.
| Property | Value | Purpose |
|---|---|---|
| hibernate.cache.region.factory_class | jcache | Use the JCache integration |
| hibernate.javax.cache.provider | org.ehcache.jsr107.EhcacheCachingProvider | Pick Ehcache when several providers are on the classpath |
| hibernate.javax.cache.uri | ehcache.xml | The provider’s configuration file, read from the classpath |
| hibernate.cache.use_query_cache | true | Allow cached query results (off by default) |
| hibernate.generate_statistics | true | Count hits, misses and puts |
The same keys go into persistence.xml, or into application.properties with the spring.jpa.properties. prefix in Spring Boot.
The ehcache.xml file defines one cache per region, with the region name as the alias. Reference data gets a size limit and a time to live of one hour.
<config xmlns="http://www.ehcache.org/v3">
<cache-template name="reference-data">
<expiry>
<ttl unit="hours">1</ttl>
</expiry>
<heap unit="entries">1000</heap>
</cache-template>
<cache alias="com.howtodoinjava.hibernate.secondlevelcache.Country" uses-template="reference-data"/>
<cache alias="com.howtodoinjava.hibernate.secondlevelcache.Country.currencies" uses-template="reference-data"/>
<cache alias="com.howtodoinjava.hibernate.secondlevelcache.Currency" uses-template="reference-data"/>
<cache alias="default-query-results-region" uses-template="reference-data"/>
<cache alias="default-update-timestamps-region">
<expiry>
<none/>
</expiry>
<heap unit="entries">1000</heap>
</cache>
</config>
A cached entity without a matching alias still works, because Hibernate creates the region with the provider’s default settings and logs HHH90001006: Missing cache region […] was created with provider-specific default policies. Those defaults have no size limit, so we declare every region.
2.3. Marking Entities as Cacheable
By default, no entity is cached. The default shared cache mode ENABLE_SELECTIVE caches only the entities marked with @Cacheable or @Cache. The annotation @Cacheable comes from Jakarta Persistence, whereas @Cache is Hibernate’s annotation that sets the concurrency strategy and, optionally, a custom region name.
@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Country {
@Id
@GeneratedValue
private Long id;
private String name;
private String capital;
@ManyToMany
@JoinTable(name = "country_currency",
joinColumns = @JoinColumn(name = "country_id"),
inverseJoinColumns = @JoinColumn(name = "currency_id"))
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Currency> currencies = new HashSet<>();
}
@Entity
@Immutable
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Currency {
@Id
@GeneratedValue
private Long id;
private String name;
}
The currencies use a @ManyToMany association because France and Germany share the Euro. Saving the data already fills the cache. The transaction that calls em.persist() for four countries and three currencies runs 15 statements (4 of them read the id sequences) and makes 7 puts, one per entity. Collections are cached on the first read, not on insert.
2.4. Choosing a Concurrency Strategy
The concurrency strategy decides what Hibernate does with the cached entry when a transaction changes the entity. We pick it per entity and per collection.
| Strategy | Use it for | What happens on update in Hibernate 7.4 |
|---|---|---|
| READ_ONLY | Data that never changes, together with @Immutable | With @Immutable, the change is ignored and no UPDATE runs. Without it, the commit fails. Deletes work. |
| NONSTRICT_READ_WRITE | Data that changes rarely, where a short stale read is acceptable | The entry is removed after the update; the next read runs a SELECT. Not cached on insert. |
| READ_WRITE | Data that can change; the usual choice | The entry is locked during the transaction and replaced with the new values at commit. |
| TRANSACTIONAL | JTA transactions with a provider that takes part in them, such as Infinispan | Cache and database change in the same transaction. |
For reference data, READ_ONLY with @Immutable is the cheapest strategy, and READ_WRITE is the safe default for everything else. For example, a currency name never changes, so Currency uses READ_ONLY, whereas a country can get a new capital, so Country uses READ_WRITE. A READ_ONLY strategy on a mutable entity triggers a warning at startup, and changing that entity fails at commit.
WARN org.hibernate.orm.cache - HHH90001003: Read-only caching was requested for mutable entity [com.howtodoinjava.hibernate.secondlevelcache.Timezone]
jakarta.persistence.RollbackException: Error while committing the transaction [Can't update read-only object]
2.5. Measuring Hits and Misses With Statistics
A cache that is configured wrong does not throw any error. The application works, and every read still goes to the database. We check the cache with Hibernate’s Statistics instead of trusting the configuration. With hibernate.generate_statistics on, the SessionFactory counts every cache access.
Statistics stats = emf.unwrap(SessionFactory.class).getStatistics();
long hits = stats.getSecondLevelCacheHitCount(); // entity and collection reads served by the cache
long misses = stats.getSecondLevelCacheMissCount(); // reads that went to the database
long puts = stats.getSecondLevelCachePutCount(); // entries written into the cache
long queryHits = stats.getQueryCacheHitCount(); // cached query results reused
long statements = stats.getPrepareStatementCount(); // SQL statements sent to the database
stats.clear(); // reset all counters
The counters prove the lookup order from section 1.1, starting with an empty cache and zero counters.
emf.runInTransaction(em -> {
em.find(Country.class, indiaId); // select ... from Country c1_0 where c1_0.id=?
// misses=1, puts=1, statements=1
em.find(Country.class, indiaId); // same object from the first level cache, counters unchanged
});
emf.runInTransaction(em -> em.find(Country.class, indiaId)); // no SQL: hits=1, statements=1
The counters for one region come from getDomainDataRegionStatistics(). Three finds in three sessions give one miss and two hits.
var region = stats.getDomainDataRegionStatistics(Country.class.getName());
long regionHits = region.getHitCount(); // 2
long regionMisses = region.getMissCount(); // 1
long regionPuts = region.getPutCount(); // 1
2.6. Caching a Collection
The @Cache annotation on the class does not cache the collections of the entity. We add @Cache to the collection field itself, as on Country.currencies in section 2.3. The collection is loaded lazily, so it reaches the cache the first time we read it.
emf.runInTransaction(em -> em.find(Country.class, indiaId).currencyNames());
// select c1_0.country_id,c1_1.id,c1_1.name from country_currency c1_0 join Currency c1_1 on c1_1.id=c1_0.currency_id where c1_0.country_id=?
// [Rupee]: Country hit, collection miss, 2 puts (collection and Rupee)
emf.runInTransaction(em -> em.find(Country.class, indiaId).currencyNames());
// no SQL, [Rupee]: 3 hits (Country, collection, Rupee)
We cache the element entity whenever we cache a collection. The collection entry holds only ids, so when we evict the Currency region and read India’s currencies again, the collection is still a hit, but Hibernate runs one more SELECT to load the Rupee by its id.
2.7. Caching Query Results
The entity cache helps only for lookups by id. A JPQL query always runs its SQL unless we cache its result too. The query cache needs hibernate.cache.use_query_cache=true, and each query opts in with a hint.
List<Country> euroCountries = em.createQuery(
"select c from Country c join c.currencies cur where cur.name = :currency order by c.name", Country.class)
.setParameter("currency", "Euro")
.setHint(HibernateHints.HINT_CACHEABLE, true)
.getResultList();
// session 1: select c1_0.id,c1_0.capital,c1_0.name from Country c1_0 join country_currency c2_0 ... where c2_1.name=? order by c1_0.name
// [France (Paris), Germany (Berlin)], query cache miss
// session 2: no SQL, [France (Paris), Germany (Berlin)], query cache hit
The result is stored per query string and parameter values. To decide whether a cached result is still valid, Hibernate keeps the time of the last change for each table in the default-update-timestamps-region. Any insert, update or delete on Country makes all cached queries on that table stale.
emf.runInTransaction(em -> em.find(Country.class, indiaId).setCapital("Delhi"));
// update Country set capital=?,name=? where id=?
euroCountries(emf); // select ... (runs again, although India is not in the result)
The query cache helps only for queries on tables that almost never change. On a table with frequent writes, every write empties the cached results, and Hibernate still spends time storing them. The timestamps region in ehcache.xml has no expiry for a related reason, because if a timestamp expires before the query results, Hibernate can serve stale results.
2.8. Keeping the Cache in Sync With the Database
Hibernate updates the cache only for changes that go through Hibernate. When our code changes India’s capital with setCapital(), the READ_WRITE entry is replaced at commit and the next session reads “Delhi” from the cache without SQL. When another program changes the capital from “New Delhi” to “Delhi” with plain JDBC, the cache keeps “New Delhi”.

The EntityManagerFactory gives us the Jakarta Persistence Cache interface for eviction, and unwrap() gives us Hibernate’s org.hibernate.Cache with more options.
| Call | What it removes |
|---|---|
| emf.getCache().evict(Country.class, indiaId) | One country |
| emf.getCache().evict(Country.class) | All countries |
| emf.getCache().evictAll() | All entity data; collections and query results stay |
| hibernateCache.evictCollectionData(“…Country.currencies”, indiaId) | One cached collection |
| hibernateCache.evictDefaultQueryRegion() | All cached query results |
| hibernateCache.evictAllRegions() | Everything: entities, collections and queries |
emf.getCache().evict(Country.class, indiaId);
boolean cached = emf.getCache().contains(Country.class, indiaId); // false
emf.runInTransaction(em -> em.find(Country.class, indiaId)); // select ... where c1_0.id=?
org.hibernate.Cache hibernateCache = emf.unwrap(SessionFactory.class).getCache();
hibernateCache.evictAllRegions();
When one read must see the database, CacheRetrieveMode.BYPASS skips the cache for that find().
Country fresh = em.find(Country.class, indiaId, CacheRetrieveMode.BYPASS); // select ... returns Delhi
Country stale = em.find(Country.class, indiaId); // in a new session: still the stale New Delhi
The mode BYPASS reads the fresh row but does not replace the stale entry, so the next normal read still gets the old value until we evict the entry.
3. Second Level Cache FAQs
3.1. Why Does the Same Session Miss the Cache After clear()?
With READ_WRITE, a session can read only entries that were put into the cache before the session started. Each entry carries a timestamp, and Hibernate compares it with the start time of the session. So a clear() followed by a second find() in the same session runs the SELECT again.
emf.runInTransaction(em -> {
Country first = em.find(Country.class, indiaId); // select ...: misses=1, puts=1
em.clear();
Country again = em.find(Country.class, indiaId); // select ... again: misses=2, hits=0
});
emf.runInTransaction(em -> em.find(Country.class, indiaId)); // no SQL: hits=1
Older Hibernate tutorials show a hit in this case. In Hibernate 7.4 with READ_WRITE, the hit comes only in a session that opens later.
3.2. Do I Need Both @Cacheable and @Cache?
No. With the default ENABLE_SELECTIVE mode, either annotation alone caches the entity. An entity with only @Cacheable and one with only @Cache were both in the cache after persist(). We still add @Cache, because it is the only place to choose the concurrency strategy per entity, and @Cacheable keeps the intent visible for Jakarta Persistence readers. The jakarta.persistence.sharedCache.mode property changes the default.
| Mode | Which entities are cached |
|---|---|
| ENABLE_SELECTIVE (default) | Only entities marked as cacheable |
| DISABLE_SELECTIVE | All entities except those with @Cacheable(false) |
| ALL | All entities |
| NONE | None; the second level cache is off |
3.3. What Replaced hibernate-ehcache and EhCacheRegionFactory?
The hibernate-ehcache module supported Ehcache 2 and ended with version 5.6.15.Final. Hibernate 6 removed it, so Ehcache 3 runs through hibernate-jcache. The old cache SPI with CacheProvider was removed even earlier, which causes the NoClassDefFoundError for CacheProvider in old setups.
| Hibernate 5 and older | Hibernate 7 |
|---|---|
| hibernate-ehcache dependency | hibernate-jcache plus ehcache with the jakarta classifier |
| hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory | hibernate.cache.region.factory_class=jcache |
| net.sf.ehcache.configurationResourceName | hibernate.javax.cache.uri |
| sessionFactory.evictEntity(name) | emf.getCache().evict(Country.class) |
| session.load() in Hibernate 5 code | em.find(); load(Class, id) no longer exists on Session |
3.4. Can I Use Caffeine Instead of Ehcache?
Yes. Caffeine also implements JCache. We replaced the Ehcache dependency with com.github.ben-manes.caffeine:jcache:3.3.0, changed the provider property, removed the ehcache.xml URI, and all 22 tests passed without other changes.
.property("hibernate.cache.region.factory_class", "jcache")
.property("hibernate.javax.cache.provider", "com.github.benmanes.caffeine.jcache.spi.CaffeineCachingProvider")
Ehcache and Caffeine keep the data in the memory of one JVM. When the application runs on several instances, each instance has its own copy, and an update on one instance does not reach the others. For more than one instance, we need a clustered provider such as Infinispan, Hazelcast or Redis (Redisson), or a short time to live.
3.5. When Should I Not Use the Second Level Cache?
The cache saves reads at the cost of memory and extra work on every write. It hurts more than it helps when the data or the access pattern does not fit the cache.
- The data changes often. Each change locks or removes the entry, and the hit rate stays low.
- Batch jobs or SQL scripts outside Hibernate change the tables. The cache serves stale rows until eviction or expiry.
- Each row is read once, as in reports and exports over large tables. The cache fills up and nothing is read twice.
- The data is per user, such as orders or carts, with millions of rows and few repeated reads.
- Bulk updates run often. A JPQL update Country … evicts the whole Country region, and a native SQL update without extra hints evicts every region, Currency included.
Countries, currencies, product categories and configuration tables are the typical fit, because they are small and read on every request, and they change a few times a year.
3.6. Is Spring’s @Cacheable the Same as the JPA @Cacheable?
No. The JPA annotation jakarta.persistence.Cacheable marks an entity for the Hibernate second level cache. The Spring annotation org.springframework.cache.annotation.Cacheable caches the return value of a Spring bean method under a key we choose, and Hibernate does not know about it. The two can be combined, but a Spring method cache is not invalidated when Hibernate updates the entity.
4. Conclusion
The second level cache keeps the column values of selected entities, collections and query results in regions shared by all sessions. Hibernate looks in the session first, then in the cache, and runs SQL only when both miss. We turn it on with hibernate-jcache and a JCache provider such as Ehcache 3, and mark reference data with @Cacheable and @Cache. We pick READ_ONLY for data that never changes and READ_WRITE for the rest, and verify the hits with Statistics. Data that other programs change needs a time to live or explicit eviction.
5. References
- Jakarta Persistence 3.2 specification: Second-Level Cache
- Cacheable JavaDoc (Jakarta Persistence 3.2)
- SharedCacheMode JavaDoc (Jakarta Persistence 3.2)
- Cache JavaDoc (Jakarta Persistence 3.2)
- Hibernate ORM 7.4 User Guide: Caching
- Hibernate ORM 7.4 User Guide: JCache
- CacheConcurrencyStrategy JavaDoc (Hibernate 7.4)
- Statistics JavaDoc (Hibernate 7.4)
- Ehcache 3 XML Configuration
- JSR 107: JCache, the Java Temporary Caching API
Happy Learning !!
why case a and case b have equal output 1 for getEntityFetchCount() method? while in case an entity is fetched from the database and in case b entity is fetched from first level cache still getEntityFetchCount() method has the same output 1. Please clarify for this one
Hi Narasimhulu,
I guess, In real world it will be useful in multi-threaded batch applications. Were multiple threads access same table. So if one thread as fetched data from the table, other threads using different sessions need not make db calls but instead fetch from ehcache.
Lokesh correct me if I am wrong. I can try it and share an example.
Thanks.
When I use @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) for pojo class then there is problem occours.
when I evict entity from session then it get removed from 1st level cache it’s fine but when I again fetch it then query get fire. I check that entity is present in 2nd level cache but still query get fire.
If I use @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY) then it works fine.
please help me to understand it
Hi I have one question like
why hibernate is not given any implementation for second level cache.
As we have so many third party providers EHCache, OSCache, SwarmCache, JBoss Cache 1.x
Is there any specific reason for this.
Can you please help me out understanding this
Thanks
Vijay
Good post.
One clarification, does the hibernate second level cache gets updated when we fire HQL update queries ?
Very useful.
One clarification, when we there is an entity in second level cache ( say for ex: Table1 ) and when I fire HQL like
HibernateSEssion.query(“update Table1 set col1= value ….”). Will this update the object in second level cache ?
Good question. I believe that second level cache will not be updated. Van you please try and share your findings.
thanks a lot…
is Second level cache Enabled by default in Hibernate ?
No.
No. you need to add the below configuration in hibernate.cfg.xml
true
Thanks, nice examples.
great
Nice and very simple to understand articles. Do you have any article explaining Hibernate architecture? Also do you have any article explaining of hibernate does fetching of many records say hundred thousands of records with loadAll() using threads?
when or how does the cacheget invalidated?
example : I retrieve an emp object from the database with max salary
and doing some work on the entity. while there is a batch tat onboards new employees and adds a new max to the table.
if i am in the same session, hibernate sends the result from the fiirst or second level cache.
so what is the indicator here ? how does it know to refresh apart from time to live attr?
If update happens outside hibernate (e.g. direct insert queries in database) then hibernate will not be able to detect if such change happen. So in this case, there should be an option in application admin panel which can invalidate all cache/selected caches.
Refer : https://docs.jboss.org/hibernate/orm/4.3/javadocs/org/hibernate/Cache.html
Any application, which is going to be used by a large group of users, is supposed to have caching enabled. Applications usually execute a lot of similar data to different type of users. If you fetch this data from database every time from database, then database will become heavily loaded and busy. To share the load, second lvl caching comes into picture. It stores data inform of indexes mostly into physical filesystem very near to server itself. So data retrieval time comes down drastically and results into higher performance.
I have set up 2nd level cache in our application.For the first call it fetches from the database and for the 2nd call it gets from cache(found out from postgres logs).The issue is if the object has boolean attributes these attributes has null when fetched from cache though there value is true/false.Does any one faced this issue please let me know. Strucked with this for almost 4 days and did not find the solution
I found the issue.We have defined custom User Types for these boolean attributes.These custom user types has to implement dissemble and assemble functions which are used using caching.We were returning null for these two functions which were causing issue.When i modified it to return the values it takes as in parameters it started working normally.
Thanks for sharing the solution Vikas.
how to enable second level cache?
where first level and second level cache stores objects, in memory or physical storage?
First level cache is always stored in memory. Second level cache depends on your implementation choice (configuration) of cache.
Really neat and short article.
Does hibernate refers to 2-level cache for Session.get(Entity.class, id) method?
It will first check in first level cache, if not there then it will check in second level cache.
Shouldn’t this be session.get instead of session.load? The latter returns a proxy object with id attached and does not hit the database whereas the former (i.e. get) always hits the database if not found in cache.
Please correct me if wrong.
session.load() return the proxy object but if row doesn’t exist it will throw ObjectNotFoundException whereas session.get() return null. For above example, both will produce the same result.
Hi Lokesh, I want create a new session factory based on some data extracted from database at runtime and close current sessionfactory. What sholud I do in this case? Please correct me if I am wrong.
It’s interesting question. First thing first.. why would someone do this? As far as implementation is concerned, nothing is impossible.
Hi Lokesh,
I have configured ehcache as you have depicted in your “Configuring ehcache post”. But In my cache it fails to load ehcache.xml . This is why by default it is picking “ehcache-1.2.3.jar!/ehcache-failsafe.xml”.
Please suggest where should I keep ehcache.xml to get it loaded and considered.
Place it anywhere in classpath i.e. “/WEB-INF/classes” folder. Or configure here: <property name=”net.sf.ehcache.configurationResourceName”>/ehcache.xml</property>
Hi Lokesh,
I have put this line in hibernate.cfg.xml “/ehcache.xml”. Accordingly also placed ehcache.xml at the same level as that of hibertnate.cfg.xml. But again its not picking this file and going to default file. In my case I am running program from eclipse directly so there is no place for “/WEB-INF/classes” folder. Please suggest how can I get ehcache.xml file noticed.
In your src folder. If still not picking up, then paste the hardcoded full path [e.g. c:/temp/ehcache.xml].
Thanks Lokesh,
I got it configured and running. Now its picking my ehcahce.xml.
Please suggest any way by which I can clear/flush second level cache. Additionally where this second level cache is created on fileSystem ?
Use any of
sf.getCache().evictEntityRegions()
sf.getCache().evictCollectionRegions()
sf.getCache().evictDefaultQueryRegion()
sf.getCache().evictQueryRegions()
Thanks Lokesh for sharing it.
You mentioned first level cache is available by default. What about second level cache. Do we need to have some configuration for the 2nd level cache.
If yes, how we do it? Can you please elaborate?
Refer here: https://howtodoinjava.com/hibernate/hibernate-ehcache-configuration-tutorial/
Hi Lokesh,
which scenario we can use first level cache since it belongs to session and will not available in other methods.
Hibernate uses first level cache mainly to reduce the number of SQL queries it needs to generate within a given transaction. For example, if an object is modified several times within the same transaction, Hibernate will generate only one SQL UPDATE statement at the end of the transaction, containing all the modifications.
Hi Loken,
Your tutorials are really useful for understanding each concept very clearly. In one of the interview they asked me how to refresh web page content that database changes every 30 minutes automatically using any caching? if possible could you please explain me with examples?
Use anyone from below:
1) https://en.wikipedia.org/wiki/Meta_refresh
2) https://developer.ibm.com/technologies/web-development/
3) https://github.com/Atmosphere/atmosphere
4) http://www.icesoft.org/wiki/display/ICE/Easy+Ajax+Push
Thanks for your reply but they were asked me using hibernate caching mechanism that is only new changes during that 30 minutes period need to get from database and existing results should get from hibernate cache and same needs to display to the user.
Then all you need to display the page from server side cache. Ans let the cache re-build or refresh at 30 minutes period.
Yes, we need to do use server side cache. if possible could you please provide me sample code how can we set time interval at server side cache.
Hey Lokesh,
thanx for the early reply….Can u suugest me one: I am implementing rest Webservices, Now i need to implement Caching for the same, I have gone through so many Articles in the net regarding the Http etcc, but i am not able to cache my rest WS, can u put some light on the same…….
I will suggest this: https://docs.jboss.org/resteasy/docs/1.2.GA/userguide/html/Cache_NoCache_CacheControl.html#server_cache
Hi Lokesh…..
I have a doubt:
My scenario: i am implementing hibernate second level caching:
I have totally different application to alter the Database, i never use my HIbernate application for insert or update, i just use for Retrieving the data. suppose i have retrieved a data and i alter the database with different application, can u tell me whether the second level cache still works for the same database which i have altered using diff application…..
Hibernate second level cache works at “SessionFactory scope/level”. So, till the time you have common SessionFactory for different sessions in your application you are good. But, in your case you have a completely different application with (assuming) different SessionFactory altogether, So in your case, second level cache WILL NOT WORK with exact behavior as in single application.
Please do not misunderstood me here. Although the caching will happen at both applications but it will be independent at both ends regardless the changes done by any of application.
Hi Lokesh Gupta, Nice tutorials your posted i Have Implemented Second level Cache Mechanism.session is not loaded from the Second level cache if your remove the department.getName() its not hitting Second level Cache Mechanism could you tel me what is reason
Can you please post the code you are playing with.
Can u please explain about concurrency strategies used to configure second level cache at class level like transactional, read-write etc . i mean which strategy to be used when?
OK
HI Lokesh
I followed your step to print out below two lines
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());
above four conditions you mentioned, it always shows 0 0
could you help me to figure it out?
Thank you
Try setting following in hibernate configuration properties
hibernate.generate_statistics————————– true
hibernate.cache.use_structured_entrie————– true
Hi, Lokesh,
Thank you for replying
I put those settings in xml file,
a,b works well, but c shows 2 0 not 1 1
do you know why it is ?
Thank you
It must me 0 2…………. not 2 0.
Reason is second level cache is already created. So DB hits are 0. Delete the second level cache from file system and you will get desired result.
Hi Lokesh,
Can you specify where this second level cache is created on file system ? and Is there any way to clear/flush this cache ?
Use the configuration like this:
<ehcache>
<diskStore path=”java.io.tmpdir”/>
<defaultCache
maxEntriesLocalHeap=”10000″
eternal=”false”
timeToIdleSeconds=”120″
timeToLiveSeconds=”120″
maxEntriesLocalDisk=”10000000″
diskExpiryThreadIntervalSeconds=”120″
memoryStoreEvictionPolicy=”LRU”
<persistence strategy=”localTempSwap”/>
/>
</ehcache>
Read this section from official documentation: https://www.ehcache.org/documentation/2.8/get-started/storage-options.html
Very very helping. Thanks. I need something which can differentiate b/w SOAP and REST web services . Can you please help me ?
https://stackoverflow.com/questions/2131965/main-differences-between-soap-and-restful-web-services-in-java
Thanks for your very nice post.
Could you answer some questions from me?
Can I disable the 2nd cache level? I know the advantages of caching mechanism but I think there are some disadvantages of it, so could tell me more about this?
Thank you a lot, I’m waiting for your response.
1) Want to disable second level cache? Don’t configure it. Simple and most obvious.
2) Yes, caching is boon to your application but it introduces certain overhead also. Everytime, you update something or delete something or even create create something, you need to invalidate certain cache blocks and re-build them so they have latest data. This step becomes more complex when cache is distributed. But believe me, advantages outweigh any such overhead.
Is cache applicable for only load methods or it is also for save/update methods.
Mean when we save an entity will it be stored in cache before saving in DB ?
NO. “Cache is only for selecting the data”. When you update something, if method return the updated entity, then in back-end it automatically fires a SELECT query which invalidate/update the first/second level caches. Otherwise if its only update operation, you will have to fetch the updated entity once again.
Hi Lokesh,
can we use load method to fetch all the records at a time instead of one record .
I believe NO. Load is used to load one entity (it’s proxy) by given identifier. For loading all records, use named queries.
Hi Gupta, Nice tutorials your posted. I want Second Level Cache Implementation by using Hiberante4 with Maven. I tried many ways. There is proper resource to implement. Please Can you provide one example by using Hibernate4.
I have posted one such implementation using OSCache. It is using Hibernate 3, but it will definitely help you to achieve your goal.
https://howtodoinjava.com/
Ih,
If i would like to use NO-SQL DB as hibernate second level cache, what i have to do..?
what are the classes i need to customise.
You can start from here:
I have written lots of RESTful WS tutorials. So far didn’t got time to explore SOAP WS. May be in future.
https://howtodoinjava.com/restful-web-service/