EntityManager为检索到的对象维护第一级缓存,但是如果你想拥有线程安全应用程序,则需要为每个事务创建和关闭entityManager。
那么,如果为每个事务创建和关闭这些实体,那么第1级缓存的重点是什么?或者,如果您在单线程中工作,则entityManager缓存是否可用?
答案 0 :(得分:5)
重点是让一个应用程序像你期望的那样工作,并且这不会像地狱一样慢。我们来举个例子:
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行修改的顺序与第一行中加载的顺序相同。如果没有第一级缓存,这是不可能的。
在D行,您不希望从数据库再次加载订单,因为它们已经在A行加载。如果没有第一级缓存,这是不可能的。
在第E行,您希望再次为订单3打印“hello”。如果没有第一级缓存,这是不可能的。
在B行,您不希望执行更新查询,因为可能会对同一实体进行许多后续修改(如下一行)。因此,您希望在事务结束时尽可能晚地将这些修改写入数据库。如果没有第一级缓存,这是不可能的。
答案 1 :(得分:4)
第一级缓存用于其他目的。它基本上是JPA放置从数据库检索的实体的上下文。
<强>性能强>
因此,要开始说明显而易见的事情,它可以避免在事务处理期间检索记录时必须检索记录,并在提高性能时使用某种形式的缓存。另外,考虑延迟加载。如何在没有缓存的情况下实现它来记录已经延迟加载的实体?
循环关系
此缓存目的对于实施适当的ORM框架至关重要。在面向对象的语言中,对象图通常具有循环关系。例如,具有Employee对象和Employee对象的Department属于Department。
如果没有上下文(也称为Unit of Work),很难跟踪您已经拥有ORMed的记录,并且最终会创建新对象,在这种情况下,您甚至可能会结束在无限循环中。
跟踪变化:提交和回滚
此外,此上下文会跟踪您对对象所做的更改,以便在事务结束时稍后可以保留或回滚它们。如果没有这样的缓存,您将被迫在发生更改时立即将更改刷新到数据库,然后您无法回滚,也无法优化将它们刷新到商店的最佳时刻。
对象标识
对象标识在ORM框架中也很重要。也就是说,如果你检索员工ID 123,那么如果你需要那个员工,你应该总是得到相同的对象,而不是一些包含相同数据的新对象。
这种类型的缓存不会被多个线程共享,如果是这样的话,你会牺牲性能并迫使每个人付出代价,即使他们可以使用单线程解决方案就好了。除了你最终会得到一个更复杂的解决方案,就像用火箭筒杀死苍蝇一样。
这就是为什么如果您需要的是共享缓存,那么您实际上需要一个二级缓存,并且还有实现。