使用JPA手动控制数据库更新

时间:2013-11-23 19:30:00

标签: java jpa entitymanager

我正在考虑在应用程序中使用JPA以保留许多对象。

应用程序的使用似乎与标准的JPA方法不一致,即更新对象的每次更改。

应用程序的使用将使得一次只有几百个对象处于活动状态,但每个对象将每秒更新几次。

虽然应用程序将对象放在内存中,但是不需要在数据库中不断更新它们,它只会是无用的IO。

是否可以使用JPA在会话中加载一些对象,并且在不影响其他实体管理对象的情况下,在内存中更改它们几分钟然后更新数据库?

如果有办法在会话之间共享某些对象,那将是最有帮助的。

2 个答案:

答案 0 :(得分:1)

如果您希望不对您的实体进行数据库更改,只需将它们与实体管理器分离即可。

  1. 要在交易期间从实体管理器中分离对象,只需使用detach方法。
  2. 如果实体未受管理(即交易结束后),则该实体无论如何都不受管理,您可以在没有额外代码的情况下对其进行任何更改。
  3. JPA 2.0规范的摘录,关于实体如何分离:

      

    如果a,则分离的实体来自事务提交   使用事务范围的容器管理的实体管理器(请参阅   第3.3节);来自事务回滚(参见第3.3.2节);的从   从持久化上下文中分离实体;清除   持久化背景;关闭实体经理;或来自   序列化实体或以其他方式通过值传递实体 - 例如,到   一个单独的应用层,通过远程接口等。

    然后在决定更改数据库时,只需合并分离的实体:entityManager.merge(entity);

    我认为,你错过了一些JPA背景,例如实体的状态以及entityManager的操作是什么。我建议搜索一些教程,或者阅读JPA spec中的一些章节(阅读第3.2章实体实例的生命周期 ,大约5页,我保证你会理解很多)。此外,如果您希望MERGE操作级联,JPA中也有解决方案。 对于EntityManager& JPA中的优秀介绍:the official tutorial

    <强>更新 我将尽快向您描述这些教程中很重要的内容。

    实体实例(即持久性Java对象)是托管,如果它与持久性上下文(〜一个EntityManager)相关联的话。如果它是托管的,则跟踪其更改,这意味着更改托管实体实例将同步到DB。更改将同步到DB,例如当交易完成或您致电entityManager.flush()时(请阅读第3.2.4节“与数据库同步”以获取更多详细信息)。

    合并操作实际上是用于更新和保留实体实例E1的操作。它返回一个被管实体实例E2,而传递的实体E1仍未被管理。

    另一方的分离实体不会被entityManager跟踪,这意味着在您不合并实体之前,entityManager将不会看到您所做的更改。

    这两个操作(还有一个持久的操作,我没有讨论)是你切换被管理的实体实例的状态&lt; - &gt;分离的方法。

    现在与您关于root&amp; children的问题相关:如果未配置任何内容,则在您的root上调用merge()detach()不会影响您的孩子。但是有一个级联方案可以在JPA中使用,因此例如调用entityManager.merge(root)也将在其子代上调用。当然,由您来决定哪个级联操作,哪个不是。

答案 1 :(得分:1)

您可以通过创建自己的实体管理器来控制实体的预期寿命。

目前尚不清楚您是在谈论JEE还是独立应用程序,但无论如何,您需要获得对实体经理工厂的访问权限,并从中获取实体经理。

您的实体经理将链接到持久性上下文。每次请求实体时,它都将被置于此持久性上下文中。如果您让实体管理器保持打开状态,那么只有在您第一次读取实体时才会访问数据库。接下来,您将从此缓存中获取它们。

如果使用资源本地事务,则可以控制何时将更改刷新到数据库。这样,您可以在一段时间内对上下文进行更改,然后通过提交事务或调用flush方法决定刷新它。

您可能需要阅读this another answer以更多地了解持久性上下文及其工作原理。

<强> - 编辑 -

根据您正在构建的应用程序类型,有多种方法可以访问您的实体管理器工厂。

如果这是一个独立的应用程序,你可以

EntityManagerFactory emf = Persistence.createEntityManagerFactory("unit-name");

如果您正在使用依赖注入框架,那么您可以使用它自动注入它。如果您使用的是JEE应用程序,则可以使用

自动为其注入
@PersistenceUnit(unitName="main")
private EntityManagerFactory emf;