hibernate 4 + jboss 7.1.1的奇怪的ehcache行为

时间:2014-08-14 22:39:50

标签: hibernate jboss ehcache

我已经在我的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]

任何帮助将不胜感激。

1 个答案:

答案 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();

这样你就可以确定发生了什么。