Java JPA和一级缓存,有什么意义?

Java JPA和一级缓存,有什么意义?,java,jpa,first-level-cache,Java,Jpa,First Level Cache,EntityManager为检索到的对象维护一级缓存,但如果您想使用线程安全应用程序,则需要为每个事务创建并关闭EntityManager 那么,如果为每个事务创建并关闭这些实体,那么级别1缓存有什么意义呢?或者,如果您使用单线程,entityManager缓存是可用的?关键是要有一个能像您期望的那样工作的应用程序,而且不会太慢。让我们举一个例子: Order order = em.find(Order.class, 3L); Customer customer = em.find(Custom

EntityManager为检索到的对象维护一级缓存,但如果您想使用线程安全应用程序,则需要为每个事务创建并关闭EntityManager


那么,如果为每个事务创建并关闭这些实体,那么级别1缓存有什么意义呢?或者,如果您使用单线程,entityManager缓存是可用的?

关键是要有一个能像您期望的那样工作的应用程序,而且不会太慢。让我们举一个例子:

Order order = em.find(Order.class, 3L);
Customer customer = em.find(Customer.class, 5L);
for (Order o : customer.getOrders()) { // line A
    if (o.getId().longValue == 3L) {
        o.setComment("hello"); // line B
        o.setModifier("John"); 
    }
}

System.out.println(order.getComment)); // line C

for (Order o : customer.getOrders()) { // line D
    System.out.println(o.getComment()); // line E
}
在A行,JPA执行SQL查询以加载客户的所有订单

在C行,您希望打印什么<代码>空值或
“你好”
?您希望打印“hello”,因为您在第B行修改的订单与第一行中加载的订单具有相同的ID。如果没有一级缓存,这是不可能的

在D行,您不希望再次从数据库加载订单,因为它们已经在A行加载。如果没有一级缓存,这是不可能的

在E行,您希望再次为订单3打印“hello”。如果没有一级缓存,这是不可能的


在第B行,您不希望执行更新查询,因为可能会对同一实体进行许多后续修改(如下一行)。因此,您希望这些修改尽可能晚地写入数据库,在事务结束时一次性完成。如果没有一级缓存,这是不可能的。

一级缓存还有其他用途。它基本上是JPA放置从数据库检索到的实体的上下文

性能

因此,为了开始说明显而易见的情况,它避免了在事务处理期间作为某种形式的缓存检索记录并提高性能时必须检索该记录。另外,考虑延迟加载。如果没有缓存来记录已经延迟加载的实体,您如何实现它

循环关系

这种缓存目的对于适当的ORM框架的实现至关重要。在面向对象语言中,对象图具有循环关系是很常见的。例如,具有员工对象的部门,这些员工对象属于某个部门

如果没有上下文(也称为as),就很难跟踪您已经格式化的记录,最终会创建新对象,在这种情况下,您甚至可能会进入无限循环

跟踪更改:提交和回滚

此外,此上下文还跟踪您对对象所做的更改,以便在事务结束后的某个时间点对其进行持久化或回滚。如果没有这样的缓存,您将被迫在更改发生时立即刷新数据库,然后无法回滚,也无法优化将更改刷新到存储的最佳时机

对象标识

对象标识在ORM框架中也很重要。也就是说,如果您检索到employee ID 123,那么如果在某个时候您需要该employee,那么您应该始终获得相同的对象,而不是包含相同数据的某个新对象

这种类型的缓存不能由多个线程共享,如果是这样的话,您将损害性能,并迫使每个人支付该罚金,即使他们可以使用单线程解决方案。除此之外,你最终会得到一个更复杂的解决方案,就像用火箭筒杀死一只苍蝇


这就是为什么如果您需要的是一个共享缓存,那么您实际上需要一个二级缓存,并且也有相应的实现。

谢谢您的回答。现在假设我们有两个实体,em1从thread1加载了Entity1的实例和一些依赖的Entity2实例。现在,em2正试图从thread2加载相同的Entity2实例。这里会发生什么?em2应该等待em1关闭,还是我将为已经在em1中的对象获取异常?您可以在这里回答,每个线程都有独立的工作单元,因此它们有实体的独立副本。显然,正确的做法是设计程序,使这些线程不会混合来自不同实体管理器的实体。读了那本书,你就准备好了。你很快就会回答问题的。谢谢你抽出时间。