我已经在我的webapp中使用ehcache配置了hibernate 4,它运行在Jboss 7.1.1中,并且发生了一些非常奇怪的事情:
在登录页面中,在用户登录之前,我有一个存储在数据库中的图像,我已使用以下参数缓存该图像:
<cache
name="myapp.war#myPersistenceUnit.com.model.ImageEntity"
maxElementsInMemory="100"
eternal="true"/>
实体注释如下:
@Entity
@Table(name = "Image")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class ImageEntity implements Serializable
我有一个查找实体的EJB:
@Stateless
public class ImgSessionBean {
public byte[] getImageBytes() throws IOException {
ImageEntity img = getEntityManager().find(ImageEntity.class, IMG_ID);
return img.getBytes();
}
}
一个将该方法暴露给Web的servlet:
@WebServlet(value = "/image")
public class ImageServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final int DEFAULT_BUFFER_SIZE = 10240;
@EJB
private ImgSessionBean imgBean;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
byte[] bytesImagem = imgBean.getImageBytes();
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType("image/png");
response.setContentLength(bytesImagem.length);
response.setHeader("Content-Disposition", "inline; filename=\"image.png\"");
try (BufferedOutputStream output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE)) {
output.write(bytesImagem);
}
}
}
登录页面有一个标记,用于从servlet调用方法:
<h:graphicImage value="/image" />
所以,当我第一次加载页面时,我可以在日志中看到hibernate查询数据库以获取图像。对同一页面的后续请求向我显示没有查询针对数据库运行,因此我们可以假设EhCache正在执行其工作。到目前为止,一切都按预期工作。
当我登录时,相同的图像会显示在每个受保护页面的标题中,有点像横幅或其他内容,使用相同的<h:graphicImage value="/image" />
标记。但是,如果我重新加载任何安全页面,我可以在日志中看到hibernate正在访问数据库:
/* load com.model.ImageEntity */ select
img0_.id as id88_0_,
img0_.bytes as bytes2_88_0_
from
Image img0_
where
img0_.id=?
我很难搞清楚为什么会这样。可能是因为我开始了用户会话吗?或者与交易有关的事情?
我启用了ehcache日志,但没有任何有趣的内容显示出来。
[编辑]
另一个证明缓存可以在我的登录页面上运行的证据。关于Hibernate统计信息,我已经遵循了这个(非常好的)post,这是日志告诉我的地方:
connects=0, cacheHit=0, cacheMiss=1
connects=0, cacheHit=1, cacheMiss=0
(缓存正在运行)connects=1, cacheHit=0, cacheMiss=1
我注意到,在受保护的网页上,connects
统计信息始终为1
,而在登录页面中,该值始终为0
。
这是我用来生成这些数字的代码:
org.hibernate.stat.Statistics stats = // get Statistics
long connects = -stats.getConnectCount();
long cacheHit = -stats.getSecondLevelCacheHitCount();
long cacheMiss = -stats.getSecondLevelCacheMissCount();
// Execute query
connects += stats.getConnectCount();
cacheHit += stats.getSecondLevelCacheHitCount();
cacheMiss += stats.getSecondLevelCacheMissCount();
[/编辑]
[EDIT2] 我没有显式创建会话工厂。我只是在我的EJB中注入实体管理器,如下所示:
@PersistenceContext(unitName = "populisDB")
private EntityManager entityManager;
这是我的persistence.xml
中与缓存相关的属性:
ENABLE_SELECTIVE
...
[/ EDIT2]
任何帮助将不胜感激。
答案 0 :(得分:0)
要完全确定二级缓存命中,您需要启用Hibernate统计信息:
<property name="hibernate.generate_statistics">true</property>
并且不要忘记启用二级缓存:
<property name="hibernate.cache.use_second_level_cache">true</property>
然后你需要收集它们,最好是using JMX and JConsole.
然后你需要检查二级缓存统计信息:
SecondLevelCacheStatistics cacheStats = stats.getSecondLevelCacheStatistics("myapp.war#myPersistenceUnit.com.model.ImageEntity");
cacheStats.getElementCountInMemory();
cacheStats.getEntries();
cacheStats.getHitCount();
cacheStats.getMissCount();
cacheStats.getPutCount();
这样你就可以确定发生了什么。