Skip to content
CMO & CTO
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

  • Digital Experience
    • Experience Strategy
    • Experience-Driven Commerce
    • Multi-Channel Experience
    • Personalization & Targeting
    • SEO & Performance
    • User Journey & Behavior
  • Marketing Technologies
    • Analytics & Measurement
    • Content Management Systems
    • Customer Data Platforms
    • Digital Asset Management
    • Marketing Automation
    • MarTech Stack & Strategy
    • Technology Buying & ROI
  • Software Engineering
    • Software Engineering
    • Software Architecture
    • General Software
    • Development Practices
    • Productivity & Workflow
    • Code
    • Engineering Management
    • Business of Software
    • Code
    • Digital Transformation
    • Systems Thinking
    • Technical Implementation
  • About
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

Caching with Hibernate: Second-Level Strategies

Posted on February 7, 2009 By Luis Fernandez

Your app is fast in dev and then faceplants in prod. You flip on Hibernate SQL logging and the console vomits queries. The database fans whir up like a tiny jet engine. Pages that felt instant take a coffee break. Been there. If that story feels familiar, the next move is not more indexes or a bigger server. The next move is caching with Hibernate second level cache, done with care so you keep correctness while cutting round trips.

Why Hibernate second level cache matters

Hibernate always keeps a per session cache. That is the first level cache. It is great for a single request that touches the same entity more than once. Then there is the second level cache. That one sits beyond the session. It can survive across requests and across users. It can live in memory inside your app or in a clustered store. When you fetch an entity by id, Hibernate can serve it from there with zero database calls.

Think about what your app reads all day. Product catalogs. Countries. Currencies. Feature flags. User profiles. Even heavy aggregates that users open and refresh like crazy. The second level cache turns those repetitive selects into memory lookups. The database breathes again. Latency drops. The app feels snappy. The trick is knowing what to cache and how.

There is also the query cache. Different beast. It stores result id lists for HQL or Criteria queries. Hibernate still loads each entity from the second level cache or the database. The query cache is a helper. The second level cache is the meat. You can use both, but start with entities and collections first.

Picking a provider and shaping cache regions

Out of the box you can choose providers like Ehcache, OSCache, or a cluster aware option from the JBoss family. Ehcache is the usual pick for a single node or simple cluster with minimal fuss. OSCache still shows up in older stacks. If you run a serious cluster and need replication or invalidation across nodes, look into a provider that speaks that language. Keep it simple on day one. You can change later if you keep regions tidy.

Regions are like folders for cached data. Group entities that live and die together. Put reference data in one region with long time to live. Put user generated data in a region with shorter time to live and strict concurrency. Separate large collections so they do not evict small items. Clear regions by name during deploys or maintenance windows. Clean region design makes production life easy.

Sizing matters. Memory is cheap compared to downtime, but it is not infinite. Start small and turn on stats. Watch hit rate, miss rate, and eviction count. If a region thrashes, either grow it or rethink what goes inside. Use time to live for safety. A stale profile picture is not the end of the world. A stale bank balance is. Which leads to the next topic.

Concurrency strategies without pain

Hibernate offers concurrency strategies per entity and per collection. This is where second level cache goes from neat to safe.

Read only: perfect for static or slowly changing data. Think ISO codes, countries, product categories that change monthly, marketing copy. Reads are fast and memory friendly. Writes are not allowed. If you update this kind of entity from time to time, do it through a maintenance job that evicts or restarts.

Non strict read write: fine for data that changes rarely and where a short stale window is acceptable. Hibernate will not lock cached entries on update. There can be a small time gap while it invalidates. Good for stats, counters that are not money, or content that has a soft freshness requirement. You gain speed with a tiny risk of brief staleness.

Read write: this is the safe everyday pick for data that changes often and must stay correct across threads. Hibernate uses a soft lock pattern around updates. It is more chatty than read only but reliable. User accounts, carts, orders before payment, anything people touch during normal sessions fits here.

Transactional: pairs with a fully transactional cache like a JTA aware provider. If your cache can join the same transaction as the database, this is the gold standard for correctness. Use it when your infrastructure supports it and your data is sensitive. If you are on a simple servlet container with no JTA, skip this one.

Pick the strategy per entity class based on how it changes in the real world. Bench reality, not guesses. Look at your logs. Which tables get hammered with selects. Which rows get updated per minute. This is the map for your cache plan.

Second level cache versus query cache and database tricks

The second level cache shines on lookup by id and on collections that you navigate often. The query cache shines when you repeat the same query with the same parameters. If your home page shows the ten latest posts and every visitor runs the same query, the query cache is a win. If your users open individual items and drill down, the second level cache is the workhorse.

Do not skip plain database tuning. Proper indexes beat any cache for data you always read once and never again. A tidy schema helps Hibernate too. Caching is not a band aid for a missing index on foreign keys, or for an N plus one query you can fix with a fetch plan.

What about external caches like Memcached. Great tool, different path. That is app managed caching with your own keys and protocols. Hibernate second level cache gives you automatic identity caching with zero glue code and consistent invalidation tied to the session factory. If you already run Memcached for other things, you can mix both. Keep Hibernate in charge of entities, and reserve Memcached for aggregated views or cross service data.

Clusters deserve a word. If you have many nodes, pick a provider that supports replication or invalidation. Synchronous replication can make writes slower and reads safer. Asynchronous replication makes writes fast and may serve a stale entry for a brief moment. Choose per region based on the pain you can tolerate. Not every region needs the same strictness.

Practical checklist

  • List your hottest select paths from logs. Start with the top five. Name the entities and collections involved.
  • Mark those entities with second level cache and pick a strategy. Read only for reference data. Read write for active user data. Non strict for soft stale friendly data.
  • Create clear regions. One for reference data, one for user data, one for big collections. Keep them small at first.
  • Pick a provider. Ehcache is a friendly default. For clusters, choose a provider that supports replication or invalidation and test it with real traffic.
  • Set time to live and max entries per region. Avoid gigantic caches with no bounds.
  • Turn on Hibernate statistics and provider stats. Watch hit rate and miss rate. Aim for a high hit rate in your top regions.
  • Keep the query cache off until entity caching shows wins. Then turn it on for a few specific queries with stable parameters.
  • Evict aggressively on deploy. Add a simple admin action to clear sensitive regions. It saves you during hotfix nights.
  • Watch for stampeding. If a region goes cold and many requests rebuild it at once, stagger warm up during startup or prefill from a job.
  • Do not cache volatile secrets, session tokens, or anything where a stale entry creates a security hole.
  • Review lazy loading. Avoid fetching giant collections by accident. Cache the collection only if your screens truly need it often.
  • Verify behavior under concurrency. Run a load test with writes and reads mixed. Look for contention in read write regions.
  • Document a fast off switch. A single flag to disable query cache and a per region kill switch for second level cache makes on call life better.

One extra tip: when in doubt, cache closer to the user. A small region with the last viewed items per user can save a bigger query later, and it is easier to reason about than a giant global region that tries to be everything.

Cache what you can defend with numbers and make every region earn its place.

Software Architecture Software Engineering

Post navigation

Previous post
Next post
  • Digital Experience (94)
    • Experience Strategy (19)
    • Experience-Driven Commerce (5)
    • Multi-Channel Experience (9)
    • Personalization & Targeting (21)
    • SEO & Performance (10)
  • Marketing Technologies (92)
    • Analytics & Measurement (14)
    • Content Management Systems (45)
    • Customer Data Platforms (4)
    • Digital Asset Management (8)
    • Marketing Automation (6)
    • MarTech Stack & Strategy (10)
    • Technology Buying & ROI (3)
  • Software Engineering (310)
    • Business of Software (20)
    • Code (30)
    • Development Practices (52)
    • Digital Transformation (21)
    • Engineering Management (25)
    • General Software (82)
    • Productivity & Workflow (30)
    • Software Architecture (85)
    • Technical Implementation (23)
  • 2025 (12)
  • 2024 (8)
  • 2023 (18)
  • 2022 (13)
  • 2021 (3)
  • 2020 (8)
  • 2019 (8)
  • 2018 (23)
  • 2017 (17)
  • 2016 (40)
  • 2015 (37)
  • 2014 (25)
  • 2013 (28)
  • 2012 (24)
  • 2011 (30)
  • 2010 (42)
  • 2009 (25)
  • 2008 (13)
  • 2007 (33)
  • 2006 (26)

Ab Testing Adobe Adobe Analytics Adobe Target AEM agile-methodologies Analytics architecture-patterns CDP CMS coding-practices content-marketing Content Supply Chain Conversion Optimization Core Web Vitals customer-education Customer Data Platform Customer Experience Customer Journey DAM Data Layer Data Unification documentation DXP Individualization java Martech metrics mobile-development Mobile First Multichannel Omnichannel Personalization product-strategy project-management Responsive Design Search Engine Optimization Segmentation seo spring Targeting Tracking user-experience User Journey web-development

©2025 CMO & CTO | WordPress Theme by SuperbThemes