hibernate 查询缓存 和 二级缓存 的使用是否与查询的条件有关?

前提条件是 hibernate 中 查询缓存 和 二级缓存 已经配置成功(使用的是EHCache);且在不同的session中用相同的查询语句(使用Query中的list),则查询缓存和二级缓存得到使用;然而当改变第二个session中的查询语句时未用到第一个session中的缓存?问是否hibernate的 查询缓存 和 二级缓存 的使用是否与查询的条件有关?
这是我的测试代码:
[code="java"]
public void testCache3(){
Session s = HibernateUtils.getSession() ;
s.beginTransaction() ;

    Query query = s.createQuery("from User") ;
    query.setCacheable(true) ;
            [color=darkred]//第一次查询会发出sql[/color]
    List list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;

    System.out.println("------------------------------------") ;

    s = HibernateUtils.getSession() ;
    s.beginTransaction() ;

    query = s.createQuery("from User u where u.name like 'yu9%'") ;
    query.setCacheable(true) ;
            [color=darkred]//改变查询条件时,也发出sql,为什么不是从上面的缓存中读取呢?[/color]
    list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;

   System.out.println("------------------------------------") ;

    s = HibernateUtils.getSession() ;
    s.beginTransaction() ;

    query = s.createQuery("from User u where u.name like 'yu9%'") ;
    query.setCacheable(true) ;
            [color=darkred]//与上一个的查询条件相同,不发出sql[/color]
    list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;
}

[/code]

请问是否查询缓存 只对相同的查询条件才能其作用? 还有就是 相同的查询条件,第一次用Query中的list ,第二次用Critera中的list也不能使用第一次的缓存,为何谢谢?
[b]问题补充:[/b]
前提条件是 hibernate 中 查询缓存 和 二级缓存 已经配置成功(使用的是EHCache);且在不同的session中用相同的查询语句(使用Query中的list),则查询缓存和二级缓存得到使用;然而当改变第二个session中的查询语句时未用到第一个session中的缓存?问是否hibernate的 查询缓存 和 二级缓存 的使用是否与查询的条件有关?
这是我的测试代码:
[code="java"]
public void testCache3(){
Session s = HibernateUtils.getSession() ;
s.beginTransaction() ;

    Query query = s.createQuery("from User") ;
    query.setCacheable(true) ;
            [color=darkred]//第一次查询会发出sql[/color]
    List list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;

    System.out.println("------------------------------------") ;

    s = HibernateUtils.getSession() ;
    s.beginTransaction() ;

    query = s.createQuery("from User u where u.name like 'yu9%'") ;
    query.setCacheable(true) ;
            [color=darkred]//改变查询条件时,也发出sql,为什么不是从上面的缓存中读取呢?[/color]
    list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;

   System.out.println("------------------------------------") ;

    s = HibernateUtils.getSession() ;
    s.beginTransaction() ;

    query = s.createQuery("from User u where u.name like 'yu9%'") ;
    query.setCacheable(true) ;
            [color=darkred]//与上一个的查询条件相同,不发出sql[/color]
    list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;
}

[/code]

请问是否查询缓存 只对相同的查询条件才能其作用? 还有就是 相同的查询条件,第一次用Query中的list ,第二次用Critera中的list也不能使用第一次的缓存,为何谢谢?

那么查询缓存是否可以控制,就像二级缓存一样可以指定缓存数目,生存期等?谢谢
[b]问题补充:[/b]
前提条件是 hibernate 中 查询缓存 和 二级缓存 已经配置成功(使用的是EHCache);且在不同的session中用相同的查询语句(使用Query中的list),则查询缓存和二级缓存得到使用;然而当改变第二个session中的查询语句时未用到第一个session中的缓存?问是否hibernate的 查询缓存 和 二级缓存 的使用是否与查询的条件有关?
这是我的测试代码:
[code="java"]
public void testCache3(){
Session s = HibernateUtils.getSession() ;
s.beginTransaction() ;

    Query query = s.createQuery("from User") ;
    query.setCacheable(true) ;
            [color=darkred]//第一次查询会发出sql[/color]
    List list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;

    System.out.println("------------------------------------") ;

    s = HibernateUtils.getSession() ;
    s.beginTransaction() ;

    query = s.createQuery("from User u where u.name like 'yu9%'") ;
    query.setCacheable(true) ;
            [color=darkred]//改变查询条件时,也发出sql,为什么不是从上面的缓存中读取呢?[/color]
    list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;

   System.out.println("------------------------------------") ;

    s = HibernateUtils.getSession() ;
    s.beginTransaction() ;

    query = s.createQuery("from User u where u.name like 'yu9%'") ;
    query.setCacheable(true) ;
            [color=darkred]//与上一个的查询条件相同,不发出sql[/color]
    list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;
}

[/code]

请问是否查询缓存 只对相同的查询条件才能其作用? 还有就是 相同的查询条件,第一次用Query中的list ,第二次用Critera中的list也不能使用第一次的缓存,为何谢谢?
[b]问题补充:[/b]
前提条件是 hibernate 中 查询缓存 和 二级缓存 已经配置成功(使用的是EHCache);且在不同的session中用相同的查询语句(使用Query中的list),则查询缓存和二级缓存得到使用;然而当改变第二个session中的查询语句时未用到第一个session中的缓存?问是否hibernate的 查询缓存 和 二级缓存 的使用是否与查询的条件有关?
这是我的测试代码:
[code="java"]
public void testCache3(){
Session s = HibernateUtils.getSession() ;
s.beginTransaction() ;

    Query query = s.createQuery("from User") ;
    query.setCacheable(true) ;
            [color=darkred]//第一次查询会发出sql[/color]
    List list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;

    System.out.println("------------------------------------") ;

    s = HibernateUtils.getSession() ;
    s.beginTransaction() ;

    query = s.createQuery("from User u where u.name like 'yu9%'") ;
    query.setCacheable(true) ;
            [color=darkred]//改变查询条件时,也发出sql,为什么不是从上面的缓存中读取呢?[/color]
    list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;

   System.out.println("------------------------------------") ;

    s = HibernateUtils.getSession() ;
    s.beginTransaction() ;

    query = s.createQuery("from User u where u.name like 'yu9%'") ;
    query.setCacheable(true) ;
            [color=darkred]//与上一个的查询条件相同,不发出sql[/color]
    list = query.list() ;
    for(Iterator iter=list.iterator(); iter.hasNext();){
        User user = (User)iter.next() ;
        System.out.println("user.getName ="+user.getName()) ;
    }
    s.close() ;
}

[/code]

请问是否查询缓存 只对相同的查询条件才能其作用? 还有就是 相同的查询条件,第一次用Query中的list ,第二次用Critera中的list也不能使用第一次的缓存,为何谢谢?

那么查询缓存是否可以控制,就像二级缓存一样可以指定缓存数目,生存期等?谢谢

还有一个问题刚才忘问了, 相同的查询条件,第一次用Query中的list ,第二次用Critera中的list也不能使用第一次的缓存,为何谢谢?

[quote]那么查询缓存是否可以控制,就像二级缓存一样可以指定缓存数目,生存期等?谢谢 [/quote]
好像不好精确控制,因为你不知道查出来的是什么。
查询缓存不是很有用,命中的条件太苛刻了,而且出现脏数据的可能性比较大。

查询缓存的key是SQL+查询参数,然后把它们编码,只要编码相同就会命中,所以命中率很低的。
二级缓存的Key是ID。

对了,关于查询缓存的key算法,你可以看看org.hibernate.cache.QueryKey,这个类就查询缓存的key。刚才我记错了,所谓编码,其实是俺N年前作的一个缓存的实现。Hibernate查询缓存相关的条件在QueryKey的属性中得到体现。

Hibernate的二级缓存策略的一般过程如下:
1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。
2) 把获得的所有数据对象根据ID放入到第二级缓存中。
3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。

Hibernate的Query缓存策略的过程如下:
1) Hibernate首先根据这些信息组成一个Query Key,Query Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。
2) Hibernate根据这个Query Key到Query缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。
3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空。
只有当经常使用同样的参数进行查询时,这才会有些用处

在使用查询缓存的时候,必须设置query.setCacheable(true) ;

具体来说,下面的任何一个不同都不会命中:
[code="java"]
public class QueryKey implements Serializable {
private final String sqlQueryString;
private final Type[] types;
private final Object[] values;
private final Integer firstRow;
private final Integer maxRows;
private final Map namedParameters;
private final EntityMode entityMode;
private final Set filters;

[/code]