Java 如何有效地使用EntityManager?

Java 如何有效地使用EntityManager?,java,jpa,persistence,eclipselink,Java,Jpa,Persistence,Eclipselink,最近我读了很多关于Java持久性的书籍和文章,读得越多,我就越困惑于如何正确地使用JPA和有效地使用JPA 现在,我有一个简单的服务层,用于每种类型的实体,它负责持久化、删除、搜索等。它从单例util类中获取EntityManager工厂,创建一个EntityManager,执行事务,然后关闭实体管理器。EMF仅在应用程序关闭时关闭。如果我理解正确,通过关闭EntityManager,我的所有对象(与之相关)都会分离。通过更改对象中的任何值,它们不会得到持久化,因此我认为情况就是这样 我在一本书

最近我读了很多关于Java持久性的书籍和文章,读得越多,我就越困惑于如何正确地使用JPA和有效地使用JPA

现在,我有一个简单的服务层,用于每种类型的实体,它负责持久化、删除、搜索等。它从单例util类中获取EntityManager工厂创建一个EntityManager执行事务,然后关闭实体管理器。EMF仅在应用程序关闭时关闭。如果我理解正确,通过关闭EntityManager,我的所有对象(与之相关)都会分离。通过更改对象中的任何值,它们不会得到持久化,因此我认为情况就是这样

我在一本书中读到,我应该让服务类@无状态bean,并实体管理器作为@PersistenceContext注入其中。这样,我将拥有与我拥有的许多服务类相同数量的EntityManager(或者只注入一个是否足够聪明?)。我假设当一个对象被更多的EntityManager处理时,可能会出现这种情况,这是低效的,可能会导致错误。我是否可以将EntityManager设置为一个单独的组件,它可以保存和管理所有内容,并像EMF一样贯穿整个应用程序生命周期

正如我所了解的,EntityManager应该在每个事务之后关闭,但是我对托管部分感到困惑:

就我而言:

Car car = CarService.findOneById(somelong); //this method returns an already detached object, nothing is ever in managed state
car.setColor("yellow");
CarService.update(car); //updates the db
(这对我来说甚至都没有问题,只是一个不必要的坏问题,直到懒惰抓取开始发挥作用。)

我认为它应该如何工作:

Car car = CarService.findOneById(somelong); //does not close the EM
car.setColor("yellow"); //by this call the EM detects(?) and persists the change
实现这一目标的方法是什么?哪种方法被认为是最佳实践?如果你能给我一个每一层的例子,我将不胜感激

提前谢谢你


注:我知道这个问题非常广泛,但我希望有人能把我脑海中的问号抹掉。

我不确定这是否是你期望的完整答案,但有几点提示:

创建EMF是一个困难的操作,而创建EM是一个轻量级的操作。因此,是的,EMF被推荐为单例,并且是线程安全的

EM不是线程安全的。您是对的,建议在事务完成后关闭EM,以释放您不再需要的实体和资源,但事务不必像示例中那样仅限于通过id获取对象。您可以自由地获取一个对象,并根据需要使用它(例如:在您的示例中设置coll或类似设置),然后关闭事务-只需使用特殊的
updateCarColor
服务方法即可


由于您处于JavaEE环境中,因此您更愿意将EM管理留给容器,当您在同一事务中、使用
@PersistenceContext
注入时,容器将共享相同的EM。它是由代理完成的-不是一个真正的EM被注入
EntityManager EM
字段,而是一个代理。此代理将您的呼叫传递给共享EM。如果没有活动事务,它将创建一个新的共享EM,然后将呼叫传递给它。

我不确定这是否是您期望的完整答案,但有几个提示:

创建EMF是一个困难的操作,而创建EM是一个轻量级的操作。因此,是的,EMF被推荐为单例,并且是线程安全的

EM不是线程安全的。您是对的,建议在事务完成后关闭EM,以释放您不再需要的实体和资源,但事务不必像示例中那样仅限于通过id获取对象。您可以自由地获取一个对象,并根据需要使用它(例如:在您的示例中设置coll或类似设置),然后关闭事务-只需使用特殊的
updateCarColor
服务方法即可

由于您处于JavaEE环境中,因此您更愿意将EM管理留给容器,当您在同一事务中、使用
@PersistenceContext
注入时,容器将共享相同的EM。它是由代理完成的-不是一个真正的EM被注入
EntityManager EM
字段,而是一个代理。此代理将把您的调用传递给共享EM。如果没有活动事务,它将创建一个新的共享EM,然后将调用传递给它

我在一本书中读到,我应该将服务类设置为@Stateless bean,并将EntityManager作为@PersistenceContext注入其中。这样,我将拥有与我拥有的许多服务类相同数量的EntityManager

否。您将获得绑定到当前事务的持久性上下文。简而言之,容器将执行您自己正在执行的操作,但如果服务A调用服务B,服务B调用服务C,服务D调用,并且它们都共享相同的事务上下文,那么它们也将获得相同的持久性上下文。当事务关闭时,持久性上下文将被关闭

Car car = CarService.findOneById(somelong); //does not close the EM
car.setColor("yellow"); //by this call the EM detects(?) and persists the change
这将自动使颜色更改持久化,只要您在事务内部而不是外部执行此操作

从您的描述中,我了解到您的服务并非真正的服务。它们只是DAO:它们持久化并找到单一类型的实体,不包含任何业务逻辑。这不是应该处理交易的地方。事务应该在真正的业务服务层中处理,该层实现应用程序的事务用例

例如,假设您开发了一个银行应用程序。典型的用例是不减少账户余额。或增加账户余额。或者增加银行自己的账户余额。一个典型的用例是实现账户之间的资金转移。这