我有NHibernate(用
NHibernate.Linq和
Fluent NHibernate)设置查询缓存.一切正常,直到我做session.Save(new Widget())(即sql INSERT).在那之后,该类型Widget上的所有查询都会错过查询缓存.其他实体类型的查询缓存得很好.
using (ISession session = MySessionFactory.OpenSession()) { using (var transaction = session.BeginTransaction()) { // this INSERT screws things up var widget = new Widget {Name = "Foo"}; session.Save(widget); var query = (from w in session.Query<Widget>().Cacheable() where w.Name == "Bar" select w); var fetched1 = query.FirstOrDefault(); var fetched2 = query.FirstOrDefault(); // miss?! transaction.Commit(); } }
如果我开始新的交易,问题仍然存在.如果我开始一个新的会话,问题就会消失.这似乎有点奇怪,因为我的理解是每个SessionFactory(而不是Session)重置二级缓存.
我认为这不重要,但我正在使用HashtableCacheProvider,因为我现在正在测试.
解决方法
您描述的行为是正确的(
more here).
The update timestamp cache is not updated until you commit the
transaction! This is to ensure that you will not read “uncommitted
values” from the cache.
每当我们在Cache中获得的类型发生变化时 – 缓存数据都是陈旧的…直到提交完整的事务.
想象一下,您已缓存此过滤器的结果:
var query = (from w in session.Query<Widget>().Cacheable() where w.Name == "B*" // all names starting with B select w);
后来会添加新的Widget:
var widget = new Widget {Name = "Brigitte"}; session.Save(widget); // explicit Flush is not needed,// but then,until Commit(),query will never return Brigitte session.Flush(); // to immediately execute INSERT
如果查询仍然被缓存,Brigitte将永远不会出现……
而在Transaction中,使用FirstOrDefault()的查询会立即执行 – 写操作可能会等待Flush on Commit.
由于Transaction,所有包含的操作(insert,udpate,select)都无法从缓存中获益,因为只有Transaction作为批处理才有意义.因此,在调用commit之前,不能使用缓存.
许多详细和非常有用的信息可以在这里找到:First and Second Level caching in NHibernate
The timestamp cache is updated whenever a table is written to,but in a tricky sort of way:
- When we perform the actual writing,we write a value that is somewhere in the future to the cache. So all queries that hit the
cache now will not find it,and then hit the DB to get the new data.
Since we are in the middle of transaction,they would wait until we
finish the transaction. If we are using low isolation level,and
another thread / machine attempts to put the old results back in the
cache,it wouldn’t hold,because the update timestamp is into the
future.- When we perform the commit on the transaction,we update the timestamp cache with the current value.