【发布时间】:2012-01-15 00:37:54
【问题描述】:
是否有一种可靠的方法来确定 Hibernate 查询从何处获取数据(即 sesison 缓存或二级缓存或数据库)?如果我使用以下属性配置 Hibernate:
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
我收到了大量有关运行选择的信息(尽管我不知道从哪里检索它们)。由于这是一个 Spring MVC 应用程序,并且我们所有的请求都由 Spring 控制器处理,因此我创建了以下拦截器:
public class ProfilingInterceptor implements HandlerInterceptor {
@Autowired private SessionFactory sessionFactory;
private static final String STATS = "hibernateStats";
private static final String START_TIME = "startTime";
private static final Logger LOGGER = Logger.getLogger(ProfilingInterceptor.class);
@Override public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
request.getSession().setAttribute(START_TIME, System.currentTimeMillis());
request.getSession().setAttributes(STATS, new HibernateStatistics(sessionFactory.getStatistics());
return true;
}
@Override public boolean postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
HibernateStatistics stats = (HibernateStatistics)
request.getSession().getAttribute("STATS");
stats.update(sessionFactory.getStatistics());
request.getSession().setAttribute(STATS, new HibernateStatistics(sessionFactory.getStatistics()));
LOGGER.debug(stats);
}
@Override public boolean postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
long startTime = (Long) request.getSession().getAttribute(START_TIME);
long currentTime = System.currentTimeMillis();
request.getSession().setAttribute(START_TIME, null);
long totalTime = currentTime - startTime;
LOGGER.debug("URI: " request.getRequestURI() + " Method: "
+ request.getMethod() + " took " + totalTime + "ms.");
HibernateStatistics stats = (HibernateStatistics)
request.getSession().getAttribute(STATS);
stats.update(sessionFactory.getStatistics());
LOGGER.debug(stats);
}
}
HibernateStatistics 对象如下所示(它是一个内部类):
private static final class HibernateStatistics implements Serializable {
private static final long serialVersionUID = 1L;
private long queryExecutions = 0;
private long transactions = 0;
private long entityLoads = 0;
private long connects = 0;
private long time = 0;
private double secondLevelHits = 0;
private double secondLevelMisses = 0;
private double queryHits = 0;
private double queryMisses = 0;
public HibernateStatistics(Statistics stats) {
synchronized(stats) {
queryExecutions = -stats.getQueryExecutionCount();
transactions = -stats.getTransactionCount();
entityLoads = -stats.getEntityLoadCount();
connects = -stats.getConnectCount();
secondLevelHits = -stats.getSecondLevelCacheHitCount();
secondLevelMisses = -stats.getSecondLevelCacheMissCount();
queryHits = -stats.getQueryCacheHitCount();
queryMisses = -stats.getQueryCacheMissCount();
time = -System.currentTimeMillis();
}
}
public void update(Statistics stats) {
synchronized(stats) {
queryExecutions += stats.getQueryExecutionCount();
transactions += stats.getTransactionCount();
entityLoads += stats.getEntityLoadCount();
connects += stats.getConnectCount();
secondLevelHits += stats.getSecondLevelCacheHitCount();
secondLevelMisses += stats.getSecondLevelCacheMissCount();
queryHits += stats.getQueryCacheHitCount();
queryMisses += stats.getQueryCacheMissCount();
time += System.currentTimeMillis();
}
}
@Override
public String toString() {
return "Stats"
+ "[ queries=" + queryExecutions
+ ", xactions=" + transactions
+ ", loads=" + entityLoads
+ ", connects=" + connects
+ ", queryCacheHits=" + queryHits
+ ", secondLevelCacheHits=" + secondLevelHits
+ ", time=" + time + " ]";
}
}
我一直在使用单线程测试来查找代码中可能存在 N+1 查询问题的一些情况,但此时我们的连接数和事务数在所有页面上看起来都不错。
我现在需要一个很好的方法来确定我们的二级缓存和查询缓存的有效性。问题在于 HibernateStatistics 不是线程安全的。所以当我们尝试多线程时,我可以看到这些值的一些奇怪的数字。是否像收集统计数据并将其显示在页面上以供进一步分析一样简单?
【问题讨论】:
标签: hibernate caching spring-mvc