我正在考虑在应用程序中使用JPA以保留许多对象。
应用程序的使用似乎与标准的JPA方法不一致,即更新对象的每次更改。
应用程序的使用将使得一次只有几百个对象处于活动状态,但每个对象将每秒更新几次。
虽然应用程序将对象放在内存中,但是不需要在数据库中不断更新它们,它只会是无用的IO。
是否可以使用JPA在会话中加载一些对象,并且在不影响其他实体管理对象的情况下,在内存中更改它们几分钟然后更新数据库?
如果有办法在会话之间共享某些对象,那将是最有帮助的。
答案 0 :(得分:1)
如果您希望不对您的实体进行数据库更改,只需将它们与实体管理器分离即可。
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;