如何有效地使用EntityManager?

时间:2016-08-22 10:18:42

标签: java jpa persistence eclipselink

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

现在我为每种类型的实体提供了简单的服务层,它负责持久化,删除,搜索等。它获取 EntityManagerFactory 来自 singleton 工具类,创建 EntityManager 执行交易,然后关闭 EntityManager 。 EMF仅在应用程序关闭时关闭。如果我正确理解,关闭EntityManager 我的所有对象(与之相关)都会分离。通过更改对象中的任何值,它们不会被持久化,因此我认为是这种情况。

在一本书中,我读过我应该将服务类 @Stateless beans 注入 EntityManager 作为<其中包含strong> @PersistenceContext 。这样我就拥有与我拥有的服务类相同数量的EntityManagers(或者它足够聪明,只注入一个?)。我假设当一个对象由更多EntityManagers处理时可能存在这样的情况,这是低效的,可能会导致错误。我可以使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

(这对我来说甚至都不成问题,只有不必要的坏处,直到LAZY取出才起作用。)

我认为它应该如何运作:

Car car = CarService.findOneById(somelong); //does not close the EM
car.setColor("yellow"); //by this call the EM detects(?) and persists the change

实现这一目标的方法是什么?哪种方法被认为是最佳做法?如果你能给我一个每一层的例子,我将不胜感激。

提前谢谢!

P.S。:我知道这个问题非常广泛,但我希望有人可以从我脑海中删除问号。

2 个答案:

答案 0 :(得分:1)

我不确定这是您期望的完整答案,但只是一些提示:

创建EMF是一项艰难的操作,而创建EM则是一种轻量级操作。因此,建议使用EMF作为单例,并且它的线程安全。

EM不是线程安全的。你说得对,EM建议在完成交易时关闭,以释放你不再需要的实体和资源,但交易不一定仅限于在你的例子中通过id获取一个对象。您可以自由地获取一个对象,并根据您的需要进行操作(例如,在您的示例中设置collor),然后关闭事务 - 只需使用特殊的updateCarColor服务方法即可。

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

答案 1 :(得分:1)

  

在一本书中,我读过我应该创建服务类@Stateless bean,并将EntityManager注入@PersistenceContext。这样,我拥有的EntityManagers数量与我拥有的服务类数量相同

没有。您将获得绑定到当前事务的持久性上下文。简而言之,容器将完成您自己所做的事情,除非服务A调用服务B,服务C调用服务D,调用服务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:他们坚持并找到一种类型的实体,并且不包含任何业务逻辑。那不是应该处理交易的地方。事务应在真实的业务服务层中处理,该层实现应用程序的事务用例。

例如,我们假设你开发了一个银行应用程序。典型的用例不是减少帐户的余额。或者增加帐户余额。或者增加银行自己的账户余额。一个典型的用例是在账户之间实现资金转移。这意味着单个交易必须:

  • 找到发射器帐户
  • 找到收款人帐户
  • 检查转移是否可以完成
  • 计算银行为转移而赚取的百分比
  • 减少发射器帐户余额
  • 将获得的金额添加到银行帐户
  • 增加接收方帐户余额
  • 将转移操作添加到发射器帐户
  • 将转移操作添加到接收方帐户

此用例将使用几个DAO:AccountDAO,OperationDAO,BankAccountDAO等,但所有内容都应在单个事务中完成。整个事务将使用唯一的持久化上下文,其中管理所有实体,因此所有更改都自动保留,而无需在任何DAO上调用update()