25.7. Caching
<div class="paragraph">
Hibernate has two caching layers:
</div>
<div class="ulist">
- the first-level cache (Persistence Context) which is a application-level repeatable reads.
the second-level cache which, unlike application-level caches, it doesn’t store entity aggregates but normalized dehydrated entity entries. </div>
The first-level cache is not a caching solution "per se", being more useful for ensuring
READ COMMITTED
isolation level.</div>
While the first-level cache is short lived, being cleared when the underlying
EntityManager
is closed, the second-level cache is tied to anEntityManagerFactory
. Some second-level caching providers offer support for clusters. Therefore, a node needs only to store a subset of the whole cached data.</div>
Although the second-level cache can reduce transaction response time since entities are retrieved from the cache rather than from the database, there are other options to achieve the same goal, and you should consider these alternatives prior to jumping to a second-level cache layer:
</div>
tuning the underlying database cache so that the working set fits into memory, therefore reducing Disk I/O traffic.
- optimizing database statements through JDBC batching, statement caching, indexing can reduce the average response time, therefore increasing throughput as well.
database replication is also a very valuable option to increase read-only transaction throughput </div>
After properly tuning the database, to further reduce the average response time and increase the system throughput, application-level caching becomes inevitable.
</div>
Topically, a key-value application-level cache like Memcached or Redis is a common choice to store data aggregates. If you can duplicate all data in the key-value store, you have the option of taking down the database system for maintenance without completely loosing availability since read-only traffic can still be served from the cache.
</div>
One of the main challenges of using an application-level cache is ensuring data consistency across entity aggregates. That’s where the second-level cache comes to the rescue. Being tightly integrated with Hibernate, the second-level cache can provide better data consistency since entries are cached in a normalized fashion, just like in a relational database. Changing a parent entity only requires a single entry cache update, as opposed to cache entry invalidation cascading in key-value stores.
</div>
The second-level cache provides four cache concurrency strategies:
</div>
READ_ONLY
NONSTRICT_READ_WRITE
READ_WRITE
TRANSACTIONAL
</div>READ_WRITE
is a very good default concurrency strategy since it provides strong consistency guarantees without compromising throughput. TheTRANSACTIONAL
concurrency strategy uses JTA. Hence, it’s more suitable when entities are frequently modified.</div>
Both
READ_WRITE
andTRANSACTIONAL
use write-through caching, whileNONSTRICT_READ_WRITE
is a read-through caching strategy. For this reason,NONSTRICT_READ_WRITE
is not very suitable if entities are changed frequently.</div>
When using clustering, the second-level cache entries are spread across multiple nodes. When using Infinispan distributed cache, only
READ_WRITE
andNONSTRICT_READ_WRITE
are available for read-write caches. Bear in mind thatNONSTRICT_READ_WRITE
offers a weaker consistency guarantee since stale updates are possible.</div>
</td>
For more about Hibernate Performance Tuning, check out the High-Performance Hibernate presentation from Devoxx France.
</div> </td> </tr> </table> </div> </div> </div> </div>