【问题标题】:How did an object fetched the latest value from DB without making a db call?对象如何在不进行 db 调用的情况下从 DB 中获取最新值?
【发布时间】:2021-07-16 11:18:08
【问题描述】:

我知道标题很混乱,问题也是如此。我正在使用 JPA 存储库进行 Spring Boot,但发生了一些异常行为。

我进行了一个存储库调用来获取一个对象,比如说obj1,我对其进行了一些更改,然后我将obj1 传递给了另一个函数funcInSameClass(obj1),它在同一个类中,并且我从那个函数传递了将obj1 转换为自动装配组件AutowiredClass1 的函数funcInAutowiredClass1(obj),从该组件我将obj1 的ID 传递给自动装配组件funcInAutowiredClass2(obj1.id) 的另一个函数funcInAutowiredClass2(obj1.id)。在funcInAutowiredClass2(obj1.id) 中,我调用了存储库以获取与obj1 相同的对象,并在obj1saveAndFlush 中对数据库进行了一些更改。

class MainClass {

  @Autowired
  AutowiredClass1 autowiredClass1;

  public void main() {
    //inital object after first repository call
    Object obj1 = repo.findById(id);
    //make some changes in obj1
    obj1 = repo.saveAndFlush(obj1);
    funcInTheSameClass(obj1);
    repo.saveAndFlush(obj1)
    log.info(obj1); //here also obj1 name is now XYZ
  }
  void funcInTheSameClass(Object obj1) {
    autowiredClass1.funcInAutowiredClass1(obj1);
    log.info(obj1); //here obj1 name is now XYZ
  }
}

class AutowiredClass1 {
  @Autowired
  AutowiredClass2 autowiredClass2;
  public void funcInAutowiredClasss1(Object obj1) {
    autowiredClass2.funcInAutowiredClass2(obj1.id);
    log.info(obj1); // now obj1 name is now XYZ
  }
}

class AutowiredClass2 {
  public void funcInAutowiredClasss2(int id) {
    Object obj2 = repo.findById(id);
    obj2.setName("XYZ");
    repo.saveAndFlush(obj2);
    log.info(obj2); // here I set the obj2 name as "XYZ"
  }
}

您可以看到在funcInAutowiredClass2 中,obj1 的引用没有被传递,而是从存储库中获取一个新的实体并更新并保存。那么这些变化是如何反映在 main function() 中的。

【问题讨论】:

  • vladmihalcea.com/jpa-hibernate-first-level-cache看看这篇文章,Hibernate中一级缓存是这样工作的
  • @DanilaZharenkov 你能通过问题中的例子来解释一下这个缓存是如何完成的吗?
  • 第一次调用Object obj1 = repo.findById(id); 后,您的实体存在于 PersistenceContext(L1 缓存)中。每次刷新后 - Hibernate 将持久性上下文中的实体状态与数据库中的实体状态同步。在第二次调用findById 时,Hibernate 首先检查缓存。具有此类 ID 的实体已经存在,因此 Hibernate 获取缓存的实体。同样重要的是——Hibernate 为实体使用代理,您的 obj1 和 obj2 是持久性上下文中同一实体的代理。这就是为什么 obj1 反映了对实体所做的所有更改
  • @DanilaZharenkov 感谢您的详细解释。签出这个问题,在案例 1 中,为什么这种情况不适用于那里? stackoverflow.com/questions/68406919/…

标签: java spring spring-boot jpa spring-data-jpa


【解决方案1】:

Hibernate 有事务级缓存。当您从 db 获取项目时,它会检查缓存。如果它包含您获取该实体的实体将被返回。

小例子来演示。

@Transactional
public void someMethod() {
    MyEntity e1 = repository.findById(id);

    // Some other code

    MyEntity e2 = repository.findById(id);

    // Here e1==e2
    // So if you
    e2.setX(1);
    // you will see that
    assert e1.getX() == 1;
    // is true
}

【讨论】:

  • 但是在saveAndFlush()之后如何使更改反映在另一个类中,就像在这个问题中一样,可以理解的是,在第一个saveAndFlush()之后,条目存储在缓存中,当我们使用findById第二次返回缓存中的条目,但是当我们在obj2 中进行更改并使用saveAndFlush 那么这些更改如何反映在起始类的obj1 中?在对obj2 进行更改后,我们没有使用findById
  • 我添加了示例,希望对您有所帮助。
猜你喜欢
  • 1970-01-01
  • 2019-05-24
  • 1970-01-01
  • 2015-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多