我最近阅读了很多关于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。:我知道这个问题非常广泛,但我希望有人可以从我脑海中删除问号。
答案 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()
。