简体   繁体   English

在没有会话刷新的情况下,Hibernate标准结果会在单个事务期间更新吗?

[英]Will Hibernate criteria results update during a single transaction without session flush?

For whatever reason I have a code that in essence does something like below: it loads an instance a couple of times in a single transaction/session: 无论出于何种原因,我都有一个代码,其本质上执行以下操作:在单个事务/会话中多次加载一个实例:

@Transactional
public void fun(final String someName){
    for(int i=0; i<10; ++i) {
        SomeClass someClass = (SomeClass) session()
                    .createCriteria(SomeClass.class)
                    .add(Restrictions.eq("name", someName))
                    .uniqueResult();

        // when not found
        if(someClass == null){
           someClass = new SomeClass();
           someClass.setName(someName); // it SHOULD be found in subsequent criteria calls
       }

        process(someClass);

        session().saveOrUpdate(someClass);
        // session.flush();                     // should it be here?
    }
}

What I am not sure about is if the results of the session().createCriteria... call change during the loop. 我不确定的是session().createCriteria...调用的结果在循环期间是否更改。

It's in a transaction, and if I don't find an entity - I create it (but only once). 它是在事务中,如果我找不到实体-我会创建它(但只能创建一次)。

So during the second pass, will someClass instance ALWAYS be non-null? 因此,在第二遍过程中, someClass实例将始终为非null吗?

Of course you do not have to call flush, you should rarely execute flush. 当然,您不必调用冲洗,应该很少执行冲洗。 However the best way to proof something is with a straightforward demo, therefore I wrote a Spring Boot/Data sample and pushed it to Github . 但是,证明某事的最佳方法是使用一个简单的演示,因此我编写了一个Spring Boot / Data示例并将其推到Github上 The code is equivalent to yours, and uses Hibernate 4.3.5: 该代码与您的代码等效,并使用Hibernate 4.3.5:

@Transactional
public void createOrUpdateEmployee(String firstName, String lastName) {
  for (int i = 0; i < 10; i++) {
    Employee employee = repository.findByLastName(lastName);
    if (employee == null) {
      employee = new Employee(firstName, lastName);
      if (i > 0) {
        throw new IllegalStateException("This can never happen!");
      }
    }

    log.info(employee);

    repository.save(employee);
  }
}

The output is: 输出为:

....350  ...EmployeeService      : Employee [id=0, firstName=Andreas, lastName=Kluth, hashCode=1686333223]
....396  ...EmployeeService      : Employee [id=1, firstName=Andreas, lastName=Kluth, hashCode=1686333223]
....401  ...EmployeeService      : Employee [id=1, firstName=Andreas, lastName=Kluth, hashCode=1686333223]
....403  ...EmployeeService      : Employee [id=1, firstName=Andreas, lastName=Kluth, hashCode=1686333223]
....405  ...EmployeeService      : Employee [id=1, firstName=Andreas, lastName=Kluth, hashCode=1686333223]
....407  ...EmployeeService      : Employee [id=1, firstName=Andreas, lastName=Kluth, hashCode=1686333223]
....410  ...EmployeeService      : Employee [id=1, firstName=Andreas, lastName=Kluth, hashCode=1686333223]
....412  ...EmployeeService      : Employee [id=1, firstName=Andreas, lastName=Kluth, hashCode=1686333223]
....427  ...EmployeeService      : Employee [id=1, firstName=Andreas, lastName=Kluth, hashCode=1686333223]
....429  ...EmployeeService      : Employee [id=1, firstName=Andreas, lastName=Kluth, hashCode=1686333223]

As I would have expected the entity is retrieved from the L1 cache (hashCode stays the same) and automagically flushed as the already mentioned documentation link points out: https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Hibernate_Core_Reference_Guide/objectstate-flushing.html 就像我期望的那样,该实体是从L1缓存中检索的(hashCode保持不变),并已自动刷新,因为已提到的文档链接指出: https : //access.redhat.com/documentation/zh-CN/JBoss_Enterprise_Web_Platform/5 /html/Hibernate_Core_Reference_Guide/objectstate-flushing.html

Every time your code pass here: 每次您的代码通过此处:

 SomeClass someClass = (SomeClass) session()
                    .createCriteria(SomeClass.class)
                    .add(Restrictions.eq("name", someName))
                    .uniqueResult();

someClass will be null or have a reference to a registry in your database. someClass将为null或对数据库中注册表的引用。

(I'm assuming that .add(Restrictions.eq("name", someName)) always return an unique result, otherwise it will throw an exception) (我假设.add(Restrictions.eq("name", someName))始终返回唯一的结果,否则将引发异常)

If you are creating objects that have different @ids here process(someClass); 如果要创建具有不同@ids对象, @ids在此处进行process(someClass); then you don't need to worry. 那就不用担心了

I normally use flush , when the database generate the id dynamically , and I need the object to reflect it right now (for example, a sequence id), so I can use it. 我通常使用flush ,当数据库动态生成id时 ,我需要该对象立即反映它(例如,一个序列ID),因此可以使用它。

But in your case, I think you are providing different ids to the someClass , in the process method, so you don'need to worry about flushing. 但是对于您而言,我认为您在process方法中为someClass提供了不同的ids ,因此您不必担心刷新。


EDITED EDITED

Opsss... Opsss ...

I didn't see this line 我没看到这条线

// it SHOULD be found in subsequent criteria calls //应该在随后的条件调用中找到

Assuming this, you should flush . 假设这样, 您应该冲洗一下 So the database will reflect your new registry, otherwise, only at the end of the whole transaction all registries would be seen. 因此,数据库将反映您的新注册表,否则,只有在整个交易结束时才能看到所有注册表。


Another thing: 另一件事:

If this is the real code, you should do this: 如果这是真实的代码,则应执行以下操作:

SomeClass someClass = (SomeClass) session()
.createCriteria(SomeClass.class)
.add(Restrictions.eq("name", someName))
.uniqueResult();

for(int i=0; i<10; ++i) {

This way you don't need to go to the database at each iteration, assuming you are searching for the same object. 这样,假设您正在搜索同一对象,则无需在每次迭代时都进入数据库。 (The first level cache can help here, but if you know it's the same object you are getting, just let it outside the loop). (一级缓存可以在这里提供帮助,但是如果您知道它与所获取的对象是同一对象,请将其放在循环之外)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM