Tomcat,Hibernate,JPA和法拉盛

时间:2012-02-29 19:39:19

标签: hibernate tomcat jpa

我有一个简单的项目,我正在学习Hibernate和JPA。我已经设置并运行了项目,能够在(HSQLDB)数据库中持久化()数据,并将create()数据退出。

我在persistence.xml中启用了show_sql选项,以查看底层发生了什么。我很困惑为什么每次查询数据时都会运行SQL查询,即使没有执行其他事务/提交。

我在类的方法中使用通过Persistence.createEntityManagerFactory()创建的单个EntityManager,由我的Servlet调用。创建它时,我调用em.setFlushMode(FlushModeType.COMMIT)。

public class ThingPersist {
private static EntityManagerFactory emf;
private static EntityManager em;
public static EntityManager getEntityManager()
{
    if (emf == null)
        emf = Persistence.createEntityManagerFactory("thingPersist");
    if (em == null)
    {   
        em = emf.createEntityManager();
        em.setFlushMode(FlushModeType.COMMIT);
    }
    return em;
}
}

我的Servlet的doGet()方法查询数据(Thing类有hashCode()和equals()覆盖):

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    EntityManager em = ThingPersist.getEntityManager();
    em.setFlushMode(FlushModeType.COMMIT);
    List<Thing> things = em.createQuery("from Thing", Thing.class).getResultList();
    for (Thing thing : things)
        response.getWriter().println(thing.getSomeString());
}

然后Hibernate显示以下SQL:

Hibernate: 
select
    thing0_.id as id0_,
    thing0_.someString as someString0_ 
from
    Thing thing0_

如果我再次调用servlet,则执行相同的SQL。如果我在之后立即放置另一个相同的createQuery()块,Hibernate会报告为每个doGet()执行两次相同的SQL。

为什么Hibernate会在每次调用时查询数据库? EntityManager不应该缓存Thing对象(直到commit()更改它)?

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

刷新模式指示何时必须将对会话中的实体所做的更改写入数据库。它与查询无关。

此外,您没有在代码中启动任何交易。

最后,即使你是,当你执行查询时,Hibernate也会执行这个查询。第二次不会触发查询的唯一调用是em.find()em.getReference()。原因是

  • 第一级缓存的生命周期通常非常短(事务的持续时间),因此在同一事务中执行相同的查询两次非常罕见。
  • 根据隔离级别,查询可能会在两次调用之间返回不同的结果,因为另一个事务可能在两个查询之间进行了更改。