有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

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


共 (2) 个答案

  1. # 1 楼答案

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

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

  2. # 2 楼答案

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

    性能

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

    循环关系

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

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

    跟踪更改:提交和回滚

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

    对象标识

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

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

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