【问题标题】:Count number of queries executed by NHibernate in a unit test计算 NHibernate 在单元测试中执行的查询数
【发布时间】:2010-04-22 04:25:57
【问题描述】:

在代码的某些单元/集成测试中,我们希望检查我们的代码是否正确使用了二级缓存。

基于 Ayende 在此处提供的代码:

http://ayende.com/Blog/archive/2006/09/07/MeasuringNHibernatesQueriesPerPage.aspx

我为此编写了一个简单的类:

public class QueryCounter : IDisposable
{
    CountToContextItemsAppender _appender;

    public int QueryCount
    {
      get { return _appender.Count; }
    }

    public void Dispose()
    {
      var logger = (Logger) LogManager.GetLogger("NHibernate.SQL").Logger;
      logger.RemoveAppender(_appender);
    }

    public static QueryCounter Start()
    {
      var logger = (Logger) LogManager.GetLogger("NHibernate.SQL").Logger;

      lock (logger)
      {
        foreach (IAppender existingAppender in logger.Appenders)
        {
          if (existingAppender is CountToContextItemsAppender)
          {
            var countAppender = (CountToContextItemsAppender) existingAppender;

            countAppender.Reset();

            return new QueryCounter {_appender = (CountToContextItemsAppender) existingAppender};
          }
        }

        var newAppender = new CountToContextItemsAppender();
        logger.AddAppender(newAppender);
        logger.Level = Level.Debug;
        logger.Additivity = false;

        return new QueryCounter {_appender = newAppender};
      }
    }

    public class CountToContextItemsAppender : IAppender
    {
      int _count;

      public int Count
      {
        get { return _count; }
      }

      public void Close()
      {
      }

      public void DoAppend(LoggingEvent loggingEvent)
      {
        if (string.Empty.Equals(loggingEvent.MessageObject)) return;
        _count++;
      }

      public string Name { get; set; }

      public void Reset()
      {
        _count = 0;
      }
    }
}

预期用途:

using (var counter = QueryCounter.Start())
{
  // ... do something 
  Assert.Equal(1, counter.QueryCount); // check the query count matches our expectations
}

但它总是返回 0 作为查询计数。没有记录任何 sql 语句。

但是,如果我使用 Nhibernate Profiler 并在我的测试用例中调用它:

NHibernateProfiler.Intialize()

NHProf 使用类似的方法从 NHibernate 捕获日志输出以通过 log4net 等进行分析。然后我的 QueryCounter 开始工作。

看起来我在代码中遗漏了一些东西来正确配置 log4net 以记录 nhibernate sql ... 有没有人知道我还需要做什么才能从 Nhibernate 获取 sql 日志记录输出?

附加信息:

Logging.config:

<log4net>

  <appender name="trace" type="log4net.Appender.TraceAppender, log4net">
    <layout type="log4net.Layout.PatternLayout,log4net">
      <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &amp;lt;%P{user}&amp;gt; - %m%n" />
    </layout>
  </appender>

  <appender name="console" type="log4net.Appender.ConsoleAppender, log4net">
    <layout type="log4net.Layout.PatternLayout,log4net">
      <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &amp;lt;%P{user}&amp;gt; - %m%n" />
    </layout>
  </appender>

  <appender name="debug" type="log4net.Appender.DebugAppender, log4net">
    <layout type="log4net.Layout.PatternLayout,log4net">
      <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &amp;lt;%P{user}&amp;gt; - %m%n" />
    </layout>
  </appender>

  <logger name="NHibernate.SQL" additivity="false">
    <level value="DEBUG" />
    <appender-ref ref="ConsoleAppender" />
  </logger>

  <root>
    <priority value="DEBUG" />
    <appender-ref ref="trace" />
    <appender-ref ref="console" />
    <appender-ref ref="debug" />
  </root>

</log4net>

show_sql: 真

基于 jfneis 的响应,我编写了一个简单得多的类,它只使用 NHibernate 的工厂统计信息:

public class QueryCounter
{
  long _startCount;

  QueryCounter()
  {
  }

  public int QueryCount
  {
    get { return (int) (UnitOfWork.CurrentSession.SessionFactory.Statistics.QueryExecutionCount - _startCount); }
  }

  public static QueryCounter Start()
  {
    return new QueryCounter {_startCount = UnitOfWork.CurrentSession.SessionFactory.Statistics.QueryExecutionCount};
  }
}

启用统计信息后效果很好。

【问题讨论】:

  • 在您的休眠配置中,您是否将 show_sql 设置为 true?请问您也可以发布您的 log4net.config 吗?
  • 是的,尝试将 show_sql 设置为 true 和 false。虽然我认为 show_sql 没有使用 log4net,只是将 sql 语句转储到标准输出?我现在在最初的问题中包含了我的 log4net 配置。 NHibernateProfiler.Initialize() 然后导致我的类工作的事实向我表明,这可能是我缺少的一些编程 log4net 配置。
  • Bittercoder,我现在不在我的开发机器上,所以我不能发布代码,但是你有没有尝试使用统计来做到这一点?我也遇到过这种问题来测试 L2 和统计足以满足我的场景。回到办公室(从现在起 12 小时后)我会发布(如果仍然需要)一个完整的答案。希望这会有所帮助。
  • 你在调用 log4net.Config.XmlConfigurator.Configure();你的应用什么时候启动?
  • 应该是 。如果是这样,我会感到惊讶,只是想我会提到它。

标签: nhibernate caching count log4net nhprof


【解决方案1】:

还有另一种(更简单,IMO)方法来断言是否正在命中缓存或是否正在执行查询:使用统计信息。

首先,您必须在 NH 配置文件中启用统计信息:

 <property name="generate_statistics">true</property>

之后,您可以随时询问您的会话工厂。您已经谈到了 L2 缓存测试,所以您可以有类似的内容:

        // act
        MappedEntity retrievedEntity = session.FindById(entity.Id);
        long preCacheCount = sessionFactory.Statistics.SecondLevelCacheHitCount;
        retrievedEntity = session.FindById(entity.Id);
        long postCacheCount = sessionFactory.Statistics.SecondLevelCacheHitCount;
        // assert
        Assert.AreEqual(preCacheCount + 1, postCacheCount);

但是,如果您真正想要的是查询计数,统计界面中还有很多其他选项:

        sessionFactory.Statistics.QueryExecutionCount;
        sessionFactory.Statistics.TransactionCount;

嗯,就是这样。希望这对您有所帮助。

问候,

菲利普

【讨论】:

  • 我查看了统计信息,但没有找到任何查询统计信息 - 但我正在查看 ISessionStatistics、ISessionFactory.Statistics (IStatistics)。会试一试:)
  • 使用统计数据实现了简单的类 - 效果很好 - 感谢 José 的帮助!
  • 很高兴知道它对您有所帮助。
  • QueryExecutionCount 实际上并没有显示执行的 SELECT 语句的数量?我有一个 N+1 的情况,我正在尝试改进,单个会话 List 调用正在创建第一个选择,然后再创建 27 个。但是 QueryExecutionCount 仍然是 1。我认为 PrepareStatementCount 是你想要的。
猜你喜欢
  • 2012-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-18
  • 1970-01-01
  • 2014-10-20
相关资源
最近更新 更多