2014-03-31 71 views
6

我正在开始一个新项目,并且我完全不熟悉JPA/Hibernate的使用。我试图了解如何正确使用EntityManager。更确切地说,什么时候实例化它们,我需要多少,我应该关闭它们,我是否应该把所有事情都交易在一起?努力理解EntityManager的正确使用

无论如何,在我当前的代码中,当我尝试读取一个先前保存的实体时,出现了org.hibernate.LazyInitializationException。我会理解相反的情况(在事务中读取一个antity,然后尝试将读取的实体保存在另一个事务中,但由于事务结束,实体未被管理,因此保存失败),但我无法理解。

我把我的代码放在GitHub上(https://github.com/GaetanLeu/intl),它只是几个类。我主要在src /沙/ MessageSandbox.java,并在与以下堆栈跟踪线28失灵:

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) 

而且我从休眠说我的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直到我明白它。谢谢:)

回答

11

一个EntityManager管理着一个persistence context,其他字的数据库状态的内存快照。

What is a persistence object?

使用EntityManager加载的每个对象将在受控状态(见entity life cycle),直至关闭EM。当实体managed,它所做的所有变化都将被跟踪,然后冲洗时坚持EM。如果你访问某些懒惰获取属性,请求将被自动触发,动态的加载数据,但如果实体处于分离状态下(如EM已被关闭)访问lazy属性会导致你的错误。

您的EM的

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

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

对于CRUD应用中的生命周期通常如下:

  • 创建EM
  • 取一些实体(它们被如此管理,任何访问lazy属性将加载从DB中的数据)
  • 关闭EM(实体现在脱离,到lazy属性的任何访问将导致LazyInitializationException中)
  • 显示的数据传送给用户

在用户更新验证:

  • 创建EM
  • 打开一个交易
  • 合并(附加)更新的实体(这就是你所谓保存)(如果你已经设定了一些optmistic锁定, EM将检查实体版本,对这里的数据库)
  • 最终执行一些业务验证或其他更新
  • 提交事务并关闭EM(变化将被刷新)

请记住,EM是一个轻量级的对象,便宜的创建和销毁,而不是THREADSAFE。

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

+0

感谢您的回答。所以,如果明白你在说什么,因为我的“保存”功能和我的“读取”功能都使用他们自己的EntityManager,并且因为在保存我的实体后我没有手动刷新,所以当我的读取功能到达时, EM instanciated,我的实体没有被坚持,无法找到。但是为什么我会得到'LazyInitializationException'而不是NPE,因为它应该是整个实体没有找到的,不是? – DeleteMePlease

+0

顺便说一句,调用.persist时,为什么不立即坚持下去?有没有实际上在数据库中保留的“已提交”更改并不危险?特别是多个应用程序/ EM查询这个数据库?这里最好的做法是什么?每次坚持时都需要冲洗吗? /提交? – DeleteMePlease

+0

“当我的阅读功能达到第二个EM即刻,我的实体没有被保存,也找不到。”不,你没有误解。在评估延迟获取的属性之前,您会收到导致您关闭EM的错误。 – Gab