2013-03-12 111 views
1

我的Hibernate HQL查询似乎是返回陈旧的数据。Hibernate HQL返回陈旧的数据?

我有一个简单的java类叫做Account,它的实例映射到带有两个varchar列的用户名和姓氏的单个数据库表上。

如果我运行一个HQL查询,如:

List<?> accountList = session.createQuery("from Account where surname is null").list(); 

我找回帐户对象的列表,如预期(部分在表中的行的确有空姓字段)。

我然后设置姓在返回的对象一定非空值:

Iterator<?> accountIter = accountList.iterator(); 
while (accountIter.hasNext()) { 
    Account account = (Account) accountIter.next(); 
    log("Adding surname of Jones to : " + account.getUsername()); 
    account.setSurname("Jones"); 
} 

在这一点上,如果我再次运行HQL查询,我希望要回一个空的列表(如所有的姓都应该是非空的), 但是我回来的时候和第一次运行查询的时候一样。这不是我所期望的。

从Hibernate文档引用:

http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/

“绝对不存在约当届执行JDBC调用, 只在它们的执行顺序的保证。然而,Hibernate保证, Query.list(..)将永远不会返回陈旧或不正确的数据。

这似乎与我的代码的行为相反。查看下面清单4中的程序输出,SQL Update语句发生在所有select语句之后,所以最后一个select返回不正确的数据。 任何人都可以阐明发生了什么,或者我做错了什么?

如果我用交易包围姓氏的设置,并执行session.saveOrUpdate(account) 这一切都有效,但我认为这不是必需的。

我希望我的代码尽可能只处理域类,并且尽可能免费使用持久性代码 。

我使用Hibernate 4.1.8.Final,与Java 1.6

我完整的代码清单如下:

清单1:Main.java:

package uk.ac.york.cserv.hibernatetest; 

import java.util.Iterator; 
import java.util.List; 

import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.hibernate.cfg.Configuration; 

public class Main { 

    private static SessionFactory sf; 
    Session session; 

    public static void main(String[] args) { 
     Main main = new Main(); 
     main.doExample(); 
    } 

    public Main() { 
     sf = new Configuration() 
      .configure("hibernate-ora.cfg.xml") 
      .buildSessionFactory(); 
     session = sf.openSession(); 
    } 

    public void closeSession() { 
     session.flush(); 
     session.close(); 
    } 

    public List<?> getAccountList() { 
     return session.createQuery("from Account where surname is null").list(); 
    } 

    public void printAccountList(List<?> accountList) { 
     Iterator<?> accountIter = accountList.iterator(); 
     while (accountIter.hasNext()) { 
      System.out.println(accountIter.next()); 
     } 
    } 

    public void log(String msg) { 
     System.out.println(msg); 
    } 

    public void doExample() { 

     log("Print all accounts with null surnames..."); 
     printAccountList(getAccountList()); 

     log("Adding surnames to accounts that have null surnames..."); 
     //session.beginTransaction(); 
     Iterator<?> accountIter = getAccountList().iterator(); 
     while (accountIter.hasNext()) { 
      Account account = (Account) accountIter.next(); 
      log("Adding surname of Jones to : " + account.getUsername()); 
      account.setSurname("Jones"); 
      //session.saveOrUpdate(account); 
     } 
     //session.getTransaction().commit(); 

     log("Again print all accounts that have null surnames (should be none)..."); 
     printAccountList(getAccountList()); 

     closeSession(); 
    } 
} 

清单2:帐户.java:

package uk.ac.york.cserv.hibernatetest; 

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.Table; 

@Entity 
@Table(name="ACCOUNTS") 
public class Account { 

    @Id 
    @Column(name = "USERNAME", unique = true, nullable = false) 
    private String username; 

    @Column(name = "SURNAME") 
    private String surname; 

    public String getUsername() { 
     return username; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
    } 

    public String getSurname() { 
     return surname; 
    } 

    public void setSurname(String surname) { 
     this.surname = surname; 
    } 

    @Override 
    public String toString() { 
     return "Account [username=" + username + ", surname=" + surname + "]"; 
    } 
} 

清单3:Hibernate-ora.cfg。XML:

<hibernate-configuration> 

    <session-factory> 

     <!-- Database connection settings --> 
     <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property> 
     <property name="connection.url">jdbc:oracle:thin:@testhost:1521:test</property> 
     <property name="connection.username">testschema</property> 
     <property name="connection.password">testpassword</property> 

     <!-- JDBC connection pool (use the built-in) --> 
     <property name="connection.pool_size">1</property> 

     <!-- SQL dialect --> 
     <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property> 

     <!-- Disable the second-level cache --> 
     <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> 

     <!-- Echo all executed SQL to stdout --> 
     <property name="show_sql">true</property> 

     <!-- Names of the annotated classes --> 
     <mapping class="uk.ac.york.cserv.hibernatetest.Account"/> 

    </session-factory> 

</hibernate-configuration> 

清单4:程序的输出:

Print all accounts with null surnames... 
Hibernate: select account0_.USERNAME as USERNAME0_, account0_.SURNAME as SURNAME0_ from ACCOUNTS account0_ where account0_.SURNAME is null 
Account [username=user2, surname=null] 
Adding surnames to accounts that have null surnames... 
Hibernate: select account0_.USERNAME as USERNAME0_, account0_.SURNAME as SURNAME0_ from ACCOUNTS account0_ where account0_.SURNAME is null 
Adding surname of Jones to : user2 
Again print all accounts that have null surnames (should be none)... 
Hibernate: select account0_.USERNAME as USERNAME0_, account0_.SURNAME as SURNAME0_ from ACCOUNTS account0_ where account0_.SURNAME is null 
Account [username=user2, surname=Jones] 
Hibernate: update ACCOUNTS set SURNAME=? where USERNAME=? 

回答

2

有没有什么奇怪你描述

“此时Hibernate的行为,如果我跑了再次查询HQL,我希望得到一个空List(因为所有的姓都应该是非空的),但是相反,当我第一次运行查询时,我得到了相同的对象,这不是我所期望的。

此时,当您再次运行HQL查询时,到目前为止您尚未完成有关数据库的任何操作。这就是为什么你要获得所谓的“陈旧”数据的原因,但它实际上是表中仍未修改的最新版本

如果发出saveOrUpdate命令并关闭事务,在您的Java类中执行的操作将被持久化到数据库,以便新的HQL查询执行显示更新后的数据。我认为您误解了Hibernate在此用例中的工作方式。正是因为“Hibernate确保Query.list(..)永远不会返回失效或不正确的数据。”您会看到来自数据库的数据更新版本,从数据库的角度来看,您的Java类中的更改是“陈旧”的,并且被来自原始尚未修改的源的新“真实”数据所取代

+0

感谢您的回复。这真的有帮助。 – user2157387 2013-03-15 15:57:25