NHibernate 2nd Level Cache
NHibernate has a builtin support for caching. It sounds like a trivial feature at first, until you realize how significant it is that the underlying data access infrastructure already implements it. It means that you don’t have to worry about thread safety, propagating changes in a farm, built smart cache invalidation strategies or deal with all of the messy details that are usually along for the ride when you need to implement a non trivial infrastructure piece.
And no, it isn’t as simple as just shoving a value to the cache.
I spent quite a bit of time talking about this here, so I wouldn’t go about all the cache internals and how they work, but I’ll mention the highlights. NHibernate internally has the following sub caches:
- Entity Cache
- Collection Cache
- Query Cache
- Timestamp Cache
NHibernate make use of all of them in a fairly complex way to ensure that even though we are using the cache, we are still presenting a consistent view of the cache as a mirror of the database. The actual details of how we do it can be found here.
Another thing that NHibernate does for us when we update the cache is try to maintain the consistent view of the world even when using replicated caches used in a farm scenarios. This requires some support from the caching infrastructure, such as the ability to perform a hard lock on the values. Of the free caching providers for NHibernate, only Velocity support this, which means that when we evaluate a cache provider for NHibernate to be used, we need to take this into account.
In general, we can pretty much ignore this, but it does have some interesting implications with regards to what are the isolation guarantees that we can make based on the cache implementation that we use, the number of machines we use and the cache concurrency strategy that we use.
One thing that you should be aware of is that NHibernate currently doesn’t have transaction cache concurrency story, mostly because there is no cache provider that can give us that. As such, be aware that if you require serializable isolation level to work with your entities, you cannot use the 2nd level cache. The 2nd level cache currently guarantee only read committed (and almost guarantee repeatable read if this is the isolation level that you use in the database). Note that this guarantee is made for read-write cache concurrency mode only.