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 an EntityManagerFactory. 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. The TRANSACTIONAL concurrency strategy uses JTA. Hence, it’s more suitable when entities are frequently modified.

    </div>

    Both READ_WRITE and TRANSACTIONAL use write-through caching, while NONSTRICT_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 and NONSTRICT_READ_WRITE are available for read-write caches. Bear in mind that NONSTRICT_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>

results matching ""

    No results matching ""