在没有会话刷新的单个事务期间,Hibernate标准结果是否会更新?

时间:2014-07-18 12:25:51

标签: java spring hibernate persistence

无论出于何种原因,我都有一个代码,它本质上就像下面这样:它在一个事务/会话中加载一个实例几次:

@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?
    }
}

我不确定的是,session().createCriteria...调用的结果是否会在循环期间发生变化。

这是在交易中,如果我找不到实体 - 我创建它(但只创建一次)。

所以在第二遍中,someClass实例是否总是非空?

2 个答案:

答案 0 :(得分:3)

当然你不必调用flush,你应该很少执行flush。然而,证明某事的最佳方法是使用简单的演示,因此我编写了一个Spring Boot / Data示例并将其推送到Github。代码与您的代码相同,并使用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);
  }
}

输出结果为:

....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]

正如我所料,从L1缓存中检索实体(hashCode保持不变)并按照已提到的文档链接指出自动刷新:https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Hibernate_Core_Reference_Guide/objectstate-flushing.html

答案 1 :(得分:-1)

每次代码都在这里传递:

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

someClass将为null或对数据库中的注册表有引用。

(我假设.add(Restrictions.eq("name", someName))总是返回一个唯一的结果,否则会抛出异常)

如果要在@ids创建不同process(someClass);的对象,则无需担心。

我通常使用 flush ,当数据库动态生成 id 时,我需要对象立即反映它(例如,序列ID),所以我可以用它。

但在您的情况下,我认为您在ids方法中向someClass提供了不同的process,因此您不必担心会出现冲动。


<强> EDITED

... Opsss

我没看到这一行

  

//应该在后续的标准调用

中找到它

假设这样,你应该冲洗。因此,数据库将反映您的新注册表,否则,只有在整个事务结束时才能看到所有注册表。


另一件事:

如果这是真正的代码,你应该这样做:

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

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

这样,假设您正在搜索同一个对象,则无需在每次迭代时转到数据库。 (第一级缓存可以在这里提供帮助,但是如果你知道它与你获得的对象相同,那就让它在循环之外)。