在WEB应用中使用了Hibernate,使用session.createQuery().list()方法查询时,每次均会发SQL语句;使用session.createQuery().iterate()方法查询时使用缓存的,也就是第一次查询时会将每个对象缓存,以后查询只按ID查.
Session session = HibernateSessionFactory.getSession() ;
//Transaction tx = session.beginTransaction() ;
String queryString = "from Param";
Query queryObject = session.createQuery(queryString);
List list = queryObject.list() ;
//tx.commit() ; 
if(list!=null && list.size()>0){
for(int i=0;i<list.size();i++){
Param param = (Param)list.get(i) ;
System.out.println(param.getId()+"|"+param.getValue());
}

}
try {
Class.forName("com.mysql.jdbc.Driver") ;
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/common","root","root") ;
Statement stmt = conn.createStatement() ;
stmt.execute("update param set value=''") ;
stmt.close();
conn.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
session = HibernateSessionFactory.getSession() ;
//tx = session.beginTransaction() ;
queryObject = session.createQuery(queryString);
list = queryObject.list() ;
//tx.commit() ;
if(list!=null && list.size()>0){
for(int i=0;i<list.size();i++){
Param param = (Param)list.get(i) ;
System.out.println(param.getId()+"|"+param.getValue());
}

}两次查询的结果一样.但中间的JDBC代码部分确实已经将value值改了,请问大家这是什么原因啊?感觉list()也缓存了,但确实是发出了两句select查询.使用iterate()第二次查询只查了ID.

解决方案 »

  1.   

    问题表述很多东东看不懂有一个问题需要明确,就是两次Hb查询的session是不是同一个查询?你那句“使用iterate()第二次查询只查了ID.“ 看不懂是什么意思!?两次查询结果一样,怎么第二次又只查到了ID呢?
      

  2.   

    问题表述很多东东看不懂有一个问题需要明确,就是两次Hb查询的session是不是同一个session?你那句“使用iterate()第二次查询只查了ID.“ 看不懂是什么意思!?两次查询结果一样,怎么第二次又只查到了ID呢?
      

  3.   

    《精通hibernate java对象持久化技术详解》孙卫琴 340页说到:“
    Query 接口的iterator和list都能执行SQL,但前者在某些情况下能稍微提高查询性能。比如:
    Query query1 = session.createQuery("from Customer c");
    List result = query1.list();Query query2 = session.createQuery("from Customer c where c.age<30");
    List result2 = query2.list();当第二次执行查询时Hibernate生成的SQL为: select id,name ,age from customer wehre age < 30;
    由于在查询第二条语句时,其对应的Customer结果已经存在于Session缓存中,那么在进行第二条查询时,hiberante不需要创建新的Customer对象,只需要根据查询结果中的ID字段值返回缓存中匹配的Customer对象即可。因此第二条SQL语句可以为: SELECT id from cunstomer where age <30;那么如何达到这个效果呢,那就将 query2的 查询改为  query2.iterator()即可。”
    所以iterator的查询,应该是要跟缓存比较的,如果之前已经有缓存相关数据,那么在查询时就只查询出OID也就是对象ID,一般为表主键。然后根据OID从缓存中得到相应的整条数据对象。因此两者没什么,至于效率上,只有在表数据量比较大,字段比较多的时候才能体现出来。一般情况下没什么区别。
      

  4.   

    “Query的iterator方法首先检索ID字段,然后根据ID到hiberante的一级缓存及二级缓存中查找匹配对象,如果存在就直接将其放在查询结果中,如果不存在则执行而外的select,根据ID字段在数据库中查询。”
      

  5.   


    呵呵..是同一个session,简单描述一下情况就是:先使用hibernate query.list()查询,接着外部JDBC更新了数据,然后hibernate再查询,查询的数据仍为未更新的数据!
    我弄了两段你对比下
    public void testList(){
    Session session = HibernateSessionFactory.getSession() ;
    String queryString = "from Param";
    Query queryObject = session.createQuery(queryString);
    List list = queryObject.list() ;
    //此处查询语句为:select param0_.id as id2_, param0_.value as value2_ from common.param param0_
    //打印list,如:
    //id value
    //1  aa
    //2  bb
    //
    //此处使用JDBC更新value值,省略代码
    //
    session = HibernateSessionFactory.getSession() ;
    queryObject = session.createQuery(queryString);
    list = queryObject.list() ;
    //此处查询语句仍为:select param0_.id as id2_, param0_.value as value2_ from common.param param0_,
    //打印list仍为(注:JDBC更新后的数据hibernate没有读出来,看hibernate文档似乎又不是缓存,使用queryObject.list()才缓存)
    //id value
    //1  aa
    //2  bb
    } public void testIterate(){
    Session session = HibernateSessionFactory.getSession() ;
    String queryString = "from Param";
    Query queryObject = session.createQuery(queryString);
    Iterator it = queryObject.iterate() ;
    //此处查询语句为:select param0_.id as col_0_0_ from common.param param0_  查找出ID
    while(it.hasNext()){
    Param param = (Param)it.next(); 
    //此处查询语句为:select param0_.id as id2_0_, param0_.value as value2_0_ from common.param param0_ where param0_.id=? 根据ID找出对象并缓存
    System.out.println(param.getId()+"|"+param.getValue());
    }
    //
    //此处使用JDBC更新value值,省略代码
    //
    session = HibernateSessionFactory.getSession() ;
    queryObject = session.createQuery(queryString);
    it = queryObject.iterate() ;
    //此处查询语句为:select param0_.id as col_0_0_ from common.param param0_ 直接查出缓存对象
    while(it.hasNext()){
    Param param = (Param)it.next(); 
    System.out.println(param.getId()+"|"+param.getValue());
    }
    }
      

  6.   


    先不管是不是查询缓存,不管是list还是iterator都要查询缓存的。但iterator是先查询标识,再根据标识查实例。确实是多次查询,以就是LZ表述的现象,以下是iterator的API描述/**
     * Return the query results as an <tt>Iterator</tt>. If the query
     * contains multiple results pre row, the results are returned in
     * an instance of <tt>Object[]</tt>.<br>
     * <br>
     * Entities returned as results are initialized on demand. The first
     * SQL query returns identifiers only.<br>
     *
     * @return the result iterator
     * @throws HibernateException
     */
    public Iterator iterate() throws HibernateException;
      

  7.   

    还有,修改后查询还是上一次查询结果的原因是:Hb第一次查询了结果,存放在缓存,通过第二种方式(JDBC)更新数据后,Hb他并不知道。在一个短时间内(至少在当前session)是查询缓存的。如果你在第二次查询时,先把session关闭,再重新获取一个新的session查询结果就会变了。另外,要保证你的jdbc确实更新了数据,不要jdbc没有commit(commit不一定是手动的),怎么查就都一样了。