vac*_*ach 4 java jpa first-level-cache
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
}
Run Code Online (Sandbox Code Playgroud)
在A行,JPA执行SQL查询以加载客户的所有订单。
在C行,您希望打印什么?null还是"hello"?您希望可以打印“ hello”,因为您在B行修改的订单具有与第一行中加载的ID相同的ID。没有第一级缓存,这将是不可能的。
在D行,您不希望订单从数据库中再次加载,因为它们已经在A行中加载。没有第一级缓存,这是不可能的。
在E行,您希望再次为订单3打印“ hello”。如果没有第一级缓存,这是不可能的。
在B行,您不希望执行更新查询,因为可能会对同一实体进行许多后续修改(如下一行)。因此,您希望将这些修改在事务结束时一劳永逸地写入数据库。没有第一级缓存,这将是不可能的。
一级缓存还有其他用途。它基本上是 JPA 放置从数据库检索的实体的上下文。
表现
因此,首先要说明的是,它避免了在事务处理期间充当某种形式的缓存而检索已经检索的记录并提高性能。另外,请考虑延迟加载。如果没有缓存来记录已经延迟加载的实体,如何实现它?
循环关系
这种缓存目的对于实施适当的 ORM 框架至关重要。在面向对象语言中,对象图具有循环关系是很常见的。例如,一个部门有 Employee 对象,并且这些 Employee 对象属于一个部门。
如果没有上下文(也称为工作单元),就很难跟踪您已经对哪些记录进行 ORM 处理,并且最终会创建新对象,在这种情况下,您甚至可能会陷入无限循环。
跟踪更改:提交和回滚
此外,此上下文还会跟踪您对对象所做的更改,以便在事务结束时可以保留或回滚它们。如果没有这样的缓存,您将被迫在发生更改时立即将更改刷新到数据库,然后您无法回滚,也无法优化将它们刷新到存储的最佳时机。
对象标识
对象标识在 ORM 框架中也至关重要。也就是说,如果您检索员工 ID 123,那么如果在某个时候您需要该员工,您应该始终获得相同的对象,而不是包含相同数据的某个新对象。
这种类型的缓存不能由多个线程共享,如果是这样,您将损害性能并迫使每个人付出代价,即使他们可以很好地使用单线程解决方案。除此之外,您最终会得到一个更复杂的解决方案,就像用火箭筒杀死一只苍蝇一样。
这就是为什么如果您需要的是共享缓存,那么您实际上需要二级缓存,并且也有相应的实现。
| 归档时间: |
|
| 查看次数: |
1664 次 |
| 最近记录: |