问题描述
我正在开始一个新项目,我对 JPA/Hibernate 的使用完全陌生.我试图了解如何正确使用 EntityManager.更准确地说,什么时候实例化它们,我需要多少个,我应该关闭它们,我应该把所有东西都放到事务中吗?
I'm starting a new project and I'm totally new to JPA/Hibernate use. I'm trying to understand how to use EntityManager properly. More precisely, when to instantiate them, how many do I need, should I close them, should I put everything into transactions?
无论如何,在我当前的代码中,我在尝试读取我之前保存的实体时遇到了 org.hibernate.LazyInitializationException.我会理解相反的(在一个事务中读取 anity,然后尝试将读取的实体保存在另一个事务中,但由于事务结束,实体不受管理,因此保存失败),但我无法理解.
Anyway, in my current code, I got an org.hibernate.LazyInitializationException while trying to read an entity that I previously saved. I would understand the opposite (reading an antity in a transaction then trying to save the read entity in another transaction but since transaction is over, the entity is unmanaged so save fails), but this I can't understand.
我将我的代码放在 GitHub 上(https://github.com/GaetanLeu/intl),它只是几个类.我的主要内容在 src/sandbox/MessageSandbox.java 中,它在第 28 行失败并显示以下堆栈跟踪:
I put my code on GitHub (https://github.com/GaetanLeu/intl), it's just a couple of classes. My main is in src/sandbox/MessageSandbox.java and it fails at line 28 with the following 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 方法是否返回现有的方法?
Also I got a warning from Hibernate saying my EntityManager already exists, what happens then? Is the EntityManagerFactory.createEntityManager method returning the existing one?
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 ^^ 任何帮助将不胜感激,但请简单解释一下我对此很陌生.
Really I'm lost about when to create EntityManagers ^^ Any help would be appreciated, but please simple explanation I'm really new to this.
哦顺便说一句,我想准确地说我没有使用 Spring,我没有 EJB,我想暂时手动操作 EntityManagers,直到我理解它为止.谢谢:)
Oh BTW, I want to precise I'm not using Spring, I don't have EJBs, I want to manipulate EntityManagers manually for now until I understand it. Thanks :)
推荐答案
一个 entityManager 管理一个 持久性上下文,换言之,数据库状态的内存快照.
An entityManager manages a persistence context, in other word an in memory snapshot of the database state.
请参阅什么是持久性对象?
使用 entityManager 加载的每个对象都将处于托管状态(参见 实体生命周期) 直到您关闭 EM.当实体被管理
时,对它所做的所有更改都将被跟踪,然后在刷新 EM 时保留.如果你访问了一些延迟获取的属性,会自动触发一个请求来动态加载数据,但是如果实体处于分离状态(如果 EM 已经关闭)访问一个延迟属性会导致你得到的错误.
Every object loaded using the entityManager will be in managed state (see entity life cycle) until you close the EM. When an entity is managed
, all change made to it will be tracked and then persisted when flushing the EM. If you access some lazy fetched attribute, a request will be automatically triggered to dynamically load the data, but if the entity is in detached state (if EM have been closed) accessing a lazy attribute will lead to the error you get.
您的 EM 的范围 (/lifecycle) 取决于您的执行上下文.例如,对于 Web 应用程序,通常会为每个 http 请求创建一个 EM.
The scope (/lifecycle) of your EM depends of your execution context. For a web application for example, an EM will typically be created for each http request.
对于独立应用程序,您必须考虑数据库是否可以由另一个应用程序/线程更新.如果可以,您的持久上下文可能与数据库状态不一致,您应该为每个工作单元(事务)创建它以避免这种情况.否则,您可以为所有应用程序生命周期创建一个实例并定期刷新它.
For a standalone application, you have to mind if the database can be updated by another application/thread or not. If it can, your persistent context may not be consistent with the database state and you should create it for every unit of work (transaction) to avoid that. Otherwise you can create a single instance once for all the application lifecyle and flush it regulary.
对于 CRUD 应用程序,生命周期通常如下:
For a CRUD app the lifecycle is generally the following :
- 创建 EM
- 获取一些实体(它们被如此管理,任何对惰性属性的访问都会从数据库加载数据)
- 关闭 EM(实体现在已分离,任何对惰性属性的访问都会导致 LazyInitializationException)
- 向用户显示数据
关于用户更新验证:
- 创建 em
- 开启交易
- 合并(附加)你更新的实体(这就是你所说的保存)(如果你已经设置了一些 optmistic 锁定,em 将在此处根据数据库检查实体版本)
- 最终执行一些业务验证或其他更新
- 提交事务并关闭它们(更改将被刷新)
请记住,EM 是一种轻量级对象,创建和销毁成本低,而且不是线程安全的.
Keep is mind that EM is a lightweight object, cheap to create and destroy and NOT THREADSAFE.
顺便说一句,JPA 是一种 Java EE 规范,它是 EJB 规范(持久性部分)的一部分.它的目标是在 Java EE 容器上下文(Java EE 应用程序服务器或自 JEE 6 起的 CDI)中使用.您仍然可以通过 JPA 合约在独立模式下使用 hibernate,但即使在这种情况下,也必须考虑与 spring 耦合以利用容器管理功能.
BTW, JPA is a Java EE specification which is part of the EJB one (the persistence part). Its aim is to be used in a java EE container context (Java EE application server or CDI since JEE 6). You still can use hibernate in standalone mode through the JPA contract but even in this case, coupling with spring must be considered to take advantage of container managed features.
这篇关于努力理解 EntityManager 的正确使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!