苦苦挣扎,了解EntityManager的正确使用方法

时间:2014-03-31 21:55:05

标签: hibernate jpa entitymanager

我正在开始一个新项目,我对使用JPA / Hibernate完全不熟悉。我正在尝试了解如何正确使用EntityManager。更确切地说,何时实例化它们,我需要多少,如果我关闭它们,我应该把所有东西都放到交易中吗?

无论如何,在我当前的代码中,我在尝试读取之前保存的实体时遇到了org.hibernate.LazyInitializationException。我会理解相反的事情(在事务中读取一个antity然后尝试将读取实体保存在另一个事务中但是由于事务已经结束,实体是不受管理的,因此保存失败),但这是我无法理解的。

我把我的代码放在GitHub(https://github.com/GaetanLeu/intl)上,它只是几个类。我的主要是在src / sandbox / MessageSandbox.java中,它在第28行失败,带有以下stacktrace:

Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
    at entity.MessageKey_$$_jvstfcc_0.toString(MessageKey_$$_jvstfcc_0.java)
    at java.lang.String.valueOf(String.java:2854)
    at java.lang.StringBuilder.append(StringBuilder.java:128)
    at com.google.common.base.Present.toString(Present.java:88)
    at java.lang.String.valueOf(String.java:2854)
    at java.io.PrintStream.println(PrintStream.java:821)
    at sandbox.MessageSandbox.main(MessageSandbox.java:28)

另外我收到来自Hibernate的警告说我的EntityManager已经存在,那么会发生什么? EntityManagerFactory.createEntityManager方法是否返回现有的?

WARN: HHH000436: Entity manager factory name (intl) is already registered.  If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name'

我真的迷失了什么时候创建EntityManagers ^^任何帮助都会受到赞赏,但请简单解释我真的很新。

哦,顺便说一下,我想确切地说我没有使用Spring,我没有EJB,我想现在手动操作EntityManagers,直到我理解它为止。谢谢:))

1 个答案:

答案 0 :(得分:12)

entityManager管理persistence context,换言之,管理数据库状态的内存快照。

请参阅What is a persistence object?

使用entityManager加载的每个对象都将处于托管状态(请参阅entity life cycle),直到关闭EM。当实体为managed时,将对所有对其进行的更改进行跟踪,然后在刷新时保留EM。如果您访问一些延迟获取属性,将自动触发请求以动态加载数据,但如果实体处于分离状态(如果EM已关闭),则访问延迟属性将导致您获得的错误。

EM的范围(/生命周期)取决于您的执行上下文。例如,对于Web应用程序,通常会为每个http请求创建EM。

对于独立应用程序,您必须注意数据库是否可以由其他应用程序/线程更新。如果可以,您的持久化上下文可能与数据库状态不一致,您应该为每个工作单元(事务)创建它以避免这种情况。否则,您可以为所有应用程序生命周期创建一个实例,并定期刷新它。

对于CRUD应用程序,生命周期通常如下:

  • 创建EM
  • 获取一些实体(它们是如此管理的,对lazy属性的任何访问都将从DB加载数据)
  • 关闭EM(实体现在已分离,对lazy属性的任何访问都将导致LazyInitializationException)
  • 向用户显示数据

关于用户更新验证:

  • 创建em
  • 开启交易
  • 合并(附加)您更新的实体(这就是您所谓的保存)(如果您已设置了一些optmistic锁定,则em将在此处检查实体版本与数据库)
  • 最终执行一些业务验证或其他更新
  • 提交事务并关闭em(更改将被刷新)

请记住,EM是一个轻量级对象,创建和销毁成本低廉,而且不是THREADSAFE。

BTW,JPA是Java EE规范,它是EJB的一部分(持久性部分)。其目的是在Java EE容器上下文中使用(自JEE 6以来的Java EE应用程序服务器或CDI)。您仍然可以通过JPA合同在独立模式下使用hibernate,但即使在这种情况下,也必须考虑与spring耦合以利用容器管理功能。