5

EntityManager maintains first level cache for retrieved objects, but if you want to have threadsafe aplication you're creating and closing entityManager for each transaction.

So whats the point of the level 1 cache if those entities are created and closed for every transaction? Or entityManager cache is usable if youre working in single thread?

4

2 回答 2

7

关键是要有一个像你期望的那样工作的应用程序,而且不会像地狱一样慢。举个例子:

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 行,您希望打印什么?null还是"hello"?您希望打印“hello”,因为您在 B 行修改的订单与第一行中加载的订单具有相同的 ID。如果没有一级缓存,这是不可能的。

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

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

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

于 2014-03-29T14:29:01.060 回答
5

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

表现

因此,首先要说明这一点,它避免了在事务处理期间作为某种形式的缓存检索记录并提高性能时必须检索该记录。另外,考虑延迟加载。你怎么能在没有缓存的情况下实现它来记录已经被延迟加载的实体?

循环关系

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

如果没有上下文(也称为工作单元),将很难跟踪您已经 ORMed 的哪些记录,并且您最终会创建新对象,在这种情况下,您甚至可能会陷入无限循环。

跟踪更改:提交和回滚

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

对象身份

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

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

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

于 2014-03-29T14:29:17.213 回答