Hibernate:二级缓存
2013-11-10 16:11
148 查看
一级缓存:session级别的缓存,hibernate提供的。内置
二级缓存:sessionFactory级别的缓存,hibernate没有提供。需要第三方
准备工作
配置时的参考文件:
hibernate-distribution-3.6.10.Final\project\etc\hibernate.properties
* 1 集成c3p0连接池
* hibernate默认使用的自己的连接池,DriverManagerConnectionProvider,性能不佳
* 1.1导入c3p0jar包,必须是hibernate提供的jar
* 位置:%h%/lib/optional/c3p0/c3p0-0.9.1.jar
* 1.2在cfg.xml进行配置(注册) , hibernate链接提供实现类
* key:hibernate.connection.provider_class
value:org.hibernate.connection.C3P0ConnectionProvider
* 1.3配置c3p0(可选)
#hibernate.c3p0.max_size 2
#hibernate.c3p0.min_size 2
#hibernate.c3p0.timeout 5000
#hibernate.c3p0.max_statements 100
#hibernate.c3p0.idle_test_period 3000
#hibernate.c3p0.acquire_increment 2
#hibernate.c3p0.validate false
* 2 事务
* 回顾
* 特性:ACID (原子性、一致性、隔离性、持久性)
* 数据库隔离性产生隔离问题:
* 脏读:一个事务读到另一个事务没有提交的数据
* 不可重复读:一个事务读到另一个事务已经提交的数据(insert)
* 幻读:一个事务读到另一个事务已经提交的数据(update)
* 数据库事务的隔离级别
* 读未提交:read uncommitted
* 读已提交:read committed
* 可重复读:repeatable read
* 串行化:serializable
* hibernate可以对事务的隔离级别进行设置
* cfg.xml配置:hibernate.connection.isolation4
* hibernate对隔离级别的映射关系
* 读未提交:read uncommitted 1
* 读已提交:read committed 2
* 可重复读:repeatable read 4
* 串行化:serializable 8
* 3 管理session
* 管理方式(3中)
* 1 session生命周期与本地线程绑定(ThreadLocal线程本地遍历) --> ActionContext.getContext()
* 2 session生命周期与 JTA 事务绑定
* 3 委托管理
* 配置session与本地线程绑定
* 配置cfg.xml
*hibernate.current_session_context_class thread
* SessionFactory.getCurrentSession() 获得当前线程中的session对象
*默认不能使用
* 事务提交时,hibernate 从本地线程获得session,并关闭
需要配置项汇总:
1,配置c3p0,
2,配置hibernate事务的隔离级别
3,配置session线程与本地线程绑定
* 二级缓存入门
* 缓存:数据库中数据库的拷贝,物理介质通常是内存。如果内存不足,将会把内存中的数据暂存在硬盘中。
* 并发访问策略
transactional(事务型)
read-write(读写型)
nonstrict-read-write(非严格读写型)
read-only(只读型)
* 提供商
* EHCache 进程范围内的缓存,存放数据的物理介质可以是内存或硬盘
* OpenSymphony 进程范围内的缓存
* SwarmCache:集群范围内的缓存
* JBossCache:集群范围内的缓存
* 二级缓存的配置
* 1 导入jar包
* 核心jar : ehcache-1.5.0.jar
* 依赖jar
* backport-util-concurrent-2.1.jar
* commons-logging-1.1.1.jar
* 2 通知hibernate开启二级缓存
* 在cfg.xml配置 :hibernate.cache.use_second_level_cache = true
* 3 通知hibernate 需要使用二级缓存的供应商
* 在cfg.xml配置 : key:hibernate.cache.provider_class
value: org.hibernate.cache.EhCacheProvider
* 4 指定使用二级缓存类
* 第一种方式:hbm.xml文件进行配置(了解) <class><cache>
* 第二种方式:cfg.xml文件配置
* PO类:<class-cacheusage="read-write" class=""/>
* 集合对象:<collection-cacheusage="read-write" collection=""/>
* 5 添加ehcache配置文件
* 第一种
* 文件名称:ehcache-1.5.0.jar根目录,ehcache-failsafe.xml ,将此文件的名称修改为:ehcache.xml
* 使用位置:src
* 第二种
* 参考位置:%h%/project/etc/ehcache.xml
* 二级缓存细节描述
* 缓存数据区域
*类级别
* 集合级别
* 时间戳
* 查询缓存
* 二级缓存,保存类级别数据时,将以散装数据形式保存。(只缓存数据,不缓存对象)
* query.list() 可以将数据放置到一级缓存和二级缓存,但不能从一级缓存和二级缓存中获取。
* 集合级别,只保存OID
* 时间戳:用于记录数据是否已经变更,如果变更将更新缓存。
* 查询缓存:将查询语句 与 查询数据 对应缓存。使用Query语句进行查询(Criteria语句)
* 注意:hibernate默认查询缓存不使用
* 1 cfg.xml配置查询缓存 :hibernate.cache.use_query_cache true
* 2 每一次查询时都需要注明,需要使用查询缓存。
query.setCacheable(true);
* 二级缓存配置文件:ehcache.xml
* <diskStore 用于配置缓存文件位置
* <defaultCache 默认缓存配置
* <cache 自定义缓存配置
二级缓存细节详解:
* 类级别
1,session1调用get方法获取Person对象实例,先从缓存中找,
2,缓存中没有实例,就去数据库找,
3,从数据库获取数据后,先将数据存放到缓存,如果设定缓存为类级别,则将数据存放在类级别缓存区,注意,类级别缓存区存放的不是对象,而只是对象里的数据,
4,将缓存的数据封装成对象返还给用户,相当于new了一个Person,这时session1调用close方法释放资源。一级缓存这时已经不存在了。
5,再开启一个session2链接,调用这个链接的get方法获取Person数据,这时会先到一级缓存中获取,一级缓存中没有,则到二级缓存中获取,
6,发现二级缓存中有数据,就直接取出,不再查询数据库(通过debug可以发现,在这里不再生成sql语句,也就说明了没有再次查询数据库)。
注意:
(1),先建立一个session,获取数据后将数据存放到了一级缓存和二级缓存,再将这个链接关闭。之后再次开启一个session链接,获取同样的数据,在没有查询数据库的情况下获取到了数据,说明了二级缓存的存在,因为此时一级缓存中已经没有相关数据了。
(2),获取的两个Person对象,会发现散列码不同,说明内存地址不同,不是同一个对象,为什么呢?因为类级别缓存只是存储对象中的数据,并不存对象,所以get只能获取Person里的数据,要变成对象,需要使用数据new一个,所以这里相当于new了两个新的person对象,所以获取到的不是同一个对象。
* 集合级别
在本例中,Person对象的PO中保存了一个set集合,存储这个Person的所有订单项,比如有3个订单。
为Person和Order设置类级别的缓存,为orderSet设置集合级别的缓存。测试!
然后再将Order的类级别缓存取消掉,再测试!
程序部分代码:
Sessionsession = SessionUtils.openSession();//获取session
Transactiontransaction = session.beginTransaction();//开启事务
Personp1 = (Person)session.get(Person.class,1);//获取id为1的Person对象,
Set<Order>orderSet = p1.getOrderSet();
Sop(orderSet.size());//查询所有的订单
for(Orderorder : orderSet) {
sop(order.getPrice());
}
transaction.commit();
session.close();
***************************************
Sessionsession2 = SessionUtils.openSession();//再次获取一个session,
Transactiontransaction2 = session2.beginTransaction();开启新的事务
Personp2 = (Person)session.get(Person.class,1);//获取id为1的Person对象,缓存获取
Set<Order>orderSet2 = p2.getOrderSet();
Sop(orderSet2.size());//查询所有的订单
for(Orderorder : orderSet2) {
sop(order.getPrice());
}
transaction.commit();
session2.close();
1,session调用get方法从缓存中获取数据,缓存中没有,就去DB中获取,获取以后存放到二级缓存的类级别缓存中,存储的只是对象中的数据,并将Person对象生成返还给用户。
2,调用person的getOrderSet().size()方法,会自动去集合级别缓存中获取集合中的对象,
3,集合级别缓存中没有数据,hibernate就生成了一条sql语句,到数据库中获取,因为Order设置了类级别缓存,而且orderSet设置了集合级别缓存,所以从数据库返回的数据会把所有的这3个Order对象的中的数据存放在类级别缓存中,
4,并在集合级别缓存中存储orderSet集合中每个元素的OID,session关闭连接。
5,由于获取p2时获取的是与p1相同的对象,所以直接从缓存中获取到p2对象,不去数据库查询,new了一个新的p2对象之后,调用了p2的getOrderSet().size()方法,与之前一样,会从集合级别缓存中获取数据,由于获取的是相同的集合,所以可以拿到所有的OID,
6,hibernate会根据这些OID去类级别缓存中查找对应的对象数据,如果查找到,则直接生成对象返回给用户集合,不再生成查询sql语句去数据库查询,用户就可以进行集合操作了,比如调用size()方法。
7,这时在hibernate.cfg.xml文件中取消掉Order的类级别缓存。再进行这个流程的操作,通过debug观察。之前的1-4步都是相同结果。
8,第5步时,p2要去集合级别缓存获取数据,同样能获取到集合中元素的OID,但是第6步拿着OID去类级别缓存中查询时会查不到数据,因为Order的类级别缓存已经取消。这时hibernate就会根据这些OID再次去数据库查询,但这次要根据所有的OID查询,现在有三个对象的OID,所以要生成3条sql语句查询。所以,缓存级别要设置得当,不然反而会造成效率的降低。
* 时间戳
依然是Person的例子,这次通过query的HQL语句更新了数据库的Person的数据,然后再次查询Person的数据,观察结果,发现查到的是更新后的数据。但在此查询的时候应该是去缓存取数据,可是缓存中的数据并没有改变,改变的只是数据库的数据,那么hibernate是如何确保获取的数据是正确的呢?就用到了时间戳。
Sessionsession = SessionUtils.openSession();
Transactiontransaction = session.beginTransaction();
Personp1 = (Person)session.get(Person.class,1);//获取id为1的person数据,执行查询
Sop(p1.getName());//打印数据
session.createQuery(“updatePerson set name=:name where id=:id”)
.setString(“name”,“小强”)
.setInteger(“id”,1).executeUpdate();
transaction.commit();
session.close();
**********************************
Sessionsession2 = SessionUtils.openSession();
Transactiontransaction2 = session2.beginTransaction();
Personp2 = (Person)session2.get(Person.class,1);//一级缓存已经不存在,从二级缓存获取
Sop(p2.getName());
transaction2.commit();
session2.close();
图示说明:
1,session.get(Person.class,1)从缓存中获取Person数据,缓存中没有,去DB中获取数据,并将数据返回到二级缓存的类级别缓存中,只保留数据,不保存对象,
2,同时会在类缓存区的这个对象的数据上生成一个时间戳,T=t1,并在时间戳缓存区中生成这个对象相同的时间戳,再根据数据new一个对象返回给p1,用户获取到实例。
3,通过session.createQuery建立更新语句,直接更新了数据库中的数据,将name修改为小强,4,同时会修改时间戳区的数据,将T=t1更新为T=t2,
5,关闭了session,再次开启一个session2,通过session2再次查询这个person对象,
6,这时hibernate会先比较时间戳区域的T(t2)与类级别缓存区的时间戳T(t1),比较t2是否大于t1,如果大于,则说明肯定修改了数据,hibernate就会再次进行查询,将类级别区的数据修改为更新后的数据,并根据数据生成对象,返回给用户。
* 查询缓存
将查询语句与对应的查询数据进行缓存(使用Query)。也就是说,本次执行了一条HQL查询,
如Query query = session.createQuery(“from Person”)
并设置使用查询缓存:query.setCacheable(true),则下次再通过query执行“from Person”时,就不再生成查询的sql语句了,直接从缓存中获取,有时也称为三级缓存。
注意:hibernate默认查询缓存不使用
1cfg.xml配置查询缓存 : hibernate.cache.use_query_cache true
2 每一次查询时都需要注明,需要使用查询缓存。
示例:
@Test
public void demo10(){
/* 默认Query
每次都查询,如果不添加setCacheable(true),则每次都生成sql查询
* 查询缓存
*/
Session session =SessionUtils.openSession();
Transaction transaction =session.beginTransaction();
Query query =session.createQuery("from Person");
query.setCacheable(true); //将查询语句 与 结果 缓存到 查询缓存中
List<Person> all = query.list();
System.out.println(all);
transaction.commit();
session.close();
/**************************************************************/
Session session2 =SessionUtils.openSession();
Transaction transaction2 = session2.beginTransaction();
Query query2 =session2.createQuery("from Person");
query2.setCacheable(true); //从查询缓存中 获取数据
List<Person> all2 = query2.list();
System.out.println(all2);
transaction2.commit();
session2.close();
}
二级缓存的配置文件:ehcache.xml文件
位置:src下
<diskStore>默认值为:java.io.tmpdir,用于配置缓存文件位置,系统临时文件的位置,
使用System.getProperty("java.io.tmpdir")可以获取, 可以直接指定自己的目录
<defaultCache>默认缓存配置
maxElementsInMemory:设置在内存中可以缓存对象的最大数量
<cache>自定义缓存配置
在hibernate的ehcache.xml文件中可以看到更多的信息,在hibernate解压目录的project\etc\ehcache.xml中
向系统目录写缓存文件的时候会比较慢,一旦jvm停止,就不再继续写入,所以在java项目下可能看到很多0kb的缓存文件,但在javaweb项目中一般就不会有事了,因为服务器启动的时间一般足够长。一般要留一些时间给jvm去写缓存。
二级缓存:sessionFactory级别的缓存,hibernate没有提供。需要第三方
准备工作
配置时的参考文件:
hibernate-distribution-3.6.10.Final\project\etc\hibernate.properties
* 1 集成c3p0连接池
* hibernate默认使用的自己的连接池,DriverManagerConnectionProvider,性能不佳
* 1.1导入c3p0jar包,必须是hibernate提供的jar
* 位置:%h%/lib/optional/c3p0/c3p0-0.9.1.jar
* 1.2在cfg.xml进行配置(注册) , hibernate链接提供实现类
* key:hibernate.connection.provider_class
value:org.hibernate.connection.C3P0ConnectionProvider
* 1.3配置c3p0(可选)
#hibernate.c3p0.max_size 2
#hibernate.c3p0.min_size 2
#hibernate.c3p0.timeout 5000
#hibernate.c3p0.max_statements 100
#hibernate.c3p0.idle_test_period 3000
#hibernate.c3p0.acquire_increment 2
#hibernate.c3p0.validate false
* 2 事务
* 回顾
* 特性:ACID (原子性、一致性、隔离性、持久性)
* 数据库隔离性产生隔离问题:
* 脏读:一个事务读到另一个事务没有提交的数据
* 不可重复读:一个事务读到另一个事务已经提交的数据(insert)
* 幻读:一个事务读到另一个事务已经提交的数据(update)
* 数据库事务的隔离级别
* 读未提交:read uncommitted
* 读已提交:read committed
* 可重复读:repeatable read
* 串行化:serializable
* hibernate可以对事务的隔离级别进行设置
* cfg.xml配置:hibernate.connection.isolation4
* hibernate对隔离级别的映射关系
* 读未提交:read uncommitted 1
* 读已提交:read committed 2
* 可重复读:repeatable read 4
* 串行化:serializable 8
* 3 管理session
* 管理方式(3中)
* 1 session生命周期与本地线程绑定(ThreadLocal线程本地遍历) --> ActionContext.getContext()
* 2 session生命周期与 JTA 事务绑定
* 3 委托管理
* 配置session与本地线程绑定
* 配置cfg.xml
*hibernate.current_session_context_class thread
* SessionFactory.getCurrentSession() 获得当前线程中的session对象
*默认不能使用
* 事务提交时,hibernate 从本地线程获得session,并关闭
需要配置项汇总:
1,配置c3p0,
2,配置hibernate事务的隔离级别
3,配置session线程与本地线程绑定
* 二级缓存入门
* 缓存:数据库中数据库的拷贝,物理介质通常是内存。如果内存不足,将会把内存中的数据暂存在硬盘中。
* 并发访问策略
transactional(事务型)
read-write(读写型)
nonstrict-read-write(非严格读写型)
read-only(只读型)
* 提供商
* EHCache 进程范围内的缓存,存放数据的物理介质可以是内存或硬盘
* OpenSymphony 进程范围内的缓存
* SwarmCache:集群范围内的缓存
* JBossCache:集群范围内的缓存
* 二级缓存的配置
* 1 导入jar包
* 核心jar : ehcache-1.5.0.jar
* 依赖jar
* backport-util-concurrent-2.1.jar
* commons-logging-1.1.1.jar
* 2 通知hibernate开启二级缓存
* 在cfg.xml配置 :hibernate.cache.use_second_level_cache = true
* 3 通知hibernate 需要使用二级缓存的供应商
* 在cfg.xml配置 : key:hibernate.cache.provider_class
value: org.hibernate.cache.EhCacheProvider
* 4 指定使用二级缓存类
* 第一种方式:hbm.xml文件进行配置(了解) <class><cache>
* 第二种方式:cfg.xml文件配置
* PO类:<class-cacheusage="read-write" class=""/>
* 集合对象:<collection-cacheusage="read-write" collection=""/>
* 5 添加ehcache配置文件
* 第一种
* 文件名称:ehcache-1.5.0.jar根目录,ehcache-failsafe.xml ,将此文件的名称修改为:ehcache.xml
* 使用位置:src
* 第二种
* 参考位置:%h%/project/etc/ehcache.xml
* 二级缓存细节描述
* 缓存数据区域
*类级别
* 集合级别
* 时间戳
* 查询缓存
* 二级缓存,保存类级别数据时,将以散装数据形式保存。(只缓存数据,不缓存对象)
* query.list() 可以将数据放置到一级缓存和二级缓存,但不能从一级缓存和二级缓存中获取。
* 集合级别,只保存OID
* 时间戳:用于记录数据是否已经变更,如果变更将更新缓存。
* 查询缓存:将查询语句 与 查询数据 对应缓存。使用Query语句进行查询(Criteria语句)
* 注意:hibernate默认查询缓存不使用
* 1 cfg.xml配置查询缓存 :hibernate.cache.use_query_cache true
* 2 每一次查询时都需要注明,需要使用查询缓存。
query.setCacheable(true);
* 二级缓存配置文件:ehcache.xml
* <diskStore 用于配置缓存文件位置
* <defaultCache 默认缓存配置
* <cache 自定义缓存配置
二级缓存细节详解:
* 类级别
1,session1调用get方法获取Person对象实例,先从缓存中找,
2,缓存中没有实例,就去数据库找,
3,从数据库获取数据后,先将数据存放到缓存,如果设定缓存为类级别,则将数据存放在类级别缓存区,注意,类级别缓存区存放的不是对象,而只是对象里的数据,
4,将缓存的数据封装成对象返还给用户,相当于new了一个Person,这时session1调用close方法释放资源。一级缓存这时已经不存在了。
5,再开启一个session2链接,调用这个链接的get方法获取Person数据,这时会先到一级缓存中获取,一级缓存中没有,则到二级缓存中获取,
6,发现二级缓存中有数据,就直接取出,不再查询数据库(通过debug可以发现,在这里不再生成sql语句,也就说明了没有再次查询数据库)。
注意:
(1),先建立一个session,获取数据后将数据存放到了一级缓存和二级缓存,再将这个链接关闭。之后再次开启一个session链接,获取同样的数据,在没有查询数据库的情况下获取到了数据,说明了二级缓存的存在,因为此时一级缓存中已经没有相关数据了。
(2),获取的两个Person对象,会发现散列码不同,说明内存地址不同,不是同一个对象,为什么呢?因为类级别缓存只是存储对象中的数据,并不存对象,所以get只能获取Person里的数据,要变成对象,需要使用数据new一个,所以这里相当于new了两个新的person对象,所以获取到的不是同一个对象。
* 集合级别
在本例中,Person对象的PO中保存了一个set集合,存储这个Person的所有订单项,比如有3个订单。
为Person和Order设置类级别的缓存,为orderSet设置集合级别的缓存。测试!
然后再将Order的类级别缓存取消掉,再测试!
程序部分代码:
Sessionsession = SessionUtils.openSession();//获取session
Transactiontransaction = session.beginTransaction();//开启事务
Personp1 = (Person)session.get(Person.class,1);//获取id为1的Person对象,
Set<Order>orderSet = p1.getOrderSet();
Sop(orderSet.size());//查询所有的订单
for(Orderorder : orderSet) {
sop(order.getPrice());
}
transaction.commit();
session.close();
***************************************
Sessionsession2 = SessionUtils.openSession();//再次获取一个session,
Transactiontransaction2 = session2.beginTransaction();开启新的事务
Personp2 = (Person)session.get(Person.class,1);//获取id为1的Person对象,缓存获取
Set<Order>orderSet2 = p2.getOrderSet();
Sop(orderSet2.size());//查询所有的订单
for(Orderorder : orderSet2) {
sop(order.getPrice());
}
transaction.commit();
session2.close();
1,session调用get方法从缓存中获取数据,缓存中没有,就去DB中获取,获取以后存放到二级缓存的类级别缓存中,存储的只是对象中的数据,并将Person对象生成返还给用户。
2,调用person的getOrderSet().size()方法,会自动去集合级别缓存中获取集合中的对象,
3,集合级别缓存中没有数据,hibernate就生成了一条sql语句,到数据库中获取,因为Order设置了类级别缓存,而且orderSet设置了集合级别缓存,所以从数据库返回的数据会把所有的这3个Order对象的中的数据存放在类级别缓存中,
4,并在集合级别缓存中存储orderSet集合中每个元素的OID,session关闭连接。
5,由于获取p2时获取的是与p1相同的对象,所以直接从缓存中获取到p2对象,不去数据库查询,new了一个新的p2对象之后,调用了p2的getOrderSet().size()方法,与之前一样,会从集合级别缓存中获取数据,由于获取的是相同的集合,所以可以拿到所有的OID,
6,hibernate会根据这些OID去类级别缓存中查找对应的对象数据,如果查找到,则直接生成对象返回给用户集合,不再生成查询sql语句去数据库查询,用户就可以进行集合操作了,比如调用size()方法。
7,这时在hibernate.cfg.xml文件中取消掉Order的类级别缓存。再进行这个流程的操作,通过debug观察。之前的1-4步都是相同结果。
8,第5步时,p2要去集合级别缓存获取数据,同样能获取到集合中元素的OID,但是第6步拿着OID去类级别缓存中查询时会查不到数据,因为Order的类级别缓存已经取消。这时hibernate就会根据这些OID再次去数据库查询,但这次要根据所有的OID查询,现在有三个对象的OID,所以要生成3条sql语句查询。所以,缓存级别要设置得当,不然反而会造成效率的降低。
* 时间戳
依然是Person的例子,这次通过query的HQL语句更新了数据库的Person的数据,然后再次查询Person的数据,观察结果,发现查到的是更新后的数据。但在此查询的时候应该是去缓存取数据,可是缓存中的数据并没有改变,改变的只是数据库的数据,那么hibernate是如何确保获取的数据是正确的呢?就用到了时间戳。
Sessionsession = SessionUtils.openSession();
Transactiontransaction = session.beginTransaction();
Personp1 = (Person)session.get(Person.class,1);//获取id为1的person数据,执行查询
Sop(p1.getName());//打印数据
session.createQuery(“updatePerson set name=:name where id=:id”)
.setString(“name”,“小强”)
.setInteger(“id”,1).executeUpdate();
transaction.commit();
session.close();
**********************************
Sessionsession2 = SessionUtils.openSession();
Transactiontransaction2 = session2.beginTransaction();
Personp2 = (Person)session2.get(Person.class,1);//一级缓存已经不存在,从二级缓存获取
Sop(p2.getName());
transaction2.commit();
session2.close();
图示说明:
1,session.get(Person.class,1)从缓存中获取Person数据,缓存中没有,去DB中获取数据,并将数据返回到二级缓存的类级别缓存中,只保留数据,不保存对象,
2,同时会在类缓存区的这个对象的数据上生成一个时间戳,T=t1,并在时间戳缓存区中生成这个对象相同的时间戳,再根据数据new一个对象返回给p1,用户获取到实例。
3,通过session.createQuery建立更新语句,直接更新了数据库中的数据,将name修改为小强,4,同时会修改时间戳区的数据,将T=t1更新为T=t2,
5,关闭了session,再次开启一个session2,通过session2再次查询这个person对象,
6,这时hibernate会先比较时间戳区域的T(t2)与类级别缓存区的时间戳T(t1),比较t2是否大于t1,如果大于,则说明肯定修改了数据,hibernate就会再次进行查询,将类级别区的数据修改为更新后的数据,并根据数据生成对象,返回给用户。
* 查询缓存
将查询语句与对应的查询数据进行缓存(使用Query)。也就是说,本次执行了一条HQL查询,
如Query query = session.createQuery(“from Person”)
并设置使用查询缓存:query.setCacheable(true),则下次再通过query执行“from Person”时,就不再生成查询的sql语句了,直接从缓存中获取,有时也称为三级缓存。
注意:hibernate默认查询缓存不使用
1cfg.xml配置查询缓存 : hibernate.cache.use_query_cache true
2 每一次查询时都需要注明,需要使用查询缓存。
示例:
@Test
public void demo10(){
/* 默认Query
每次都查询,如果不添加setCacheable(true),则每次都生成sql查询
* 查询缓存
*/
Session session =SessionUtils.openSession();
Transaction transaction =session.beginTransaction();
Query query =session.createQuery("from Person");
query.setCacheable(true); //将查询语句 与 结果 缓存到 查询缓存中
List<Person> all = query.list();
System.out.println(all);
transaction.commit();
session.close();
/**************************************************************/
Session session2 =SessionUtils.openSession();
Transaction transaction2 = session2.beginTransaction();
Query query2 =session2.createQuery("from Person");
query2.setCacheable(true); //从查询缓存中 获取数据
List<Person> all2 = query2.list();
System.out.println(all2);
transaction2.commit();
session2.close();
}
二级缓存的配置文件:ehcache.xml文件
位置:src下
<diskStore>默认值为:java.io.tmpdir,用于配置缓存文件位置,系统临时文件的位置,
使用System.getProperty("java.io.tmpdir")可以获取, 可以直接指定自己的目录
<defaultCache>默认缓存配置
maxElementsInMemory:设置在内存中可以缓存对象的最大数量
<cache>自定义缓存配置
在hibernate的ehcache.xml文件中可以看到更多的信息,在hibernate解压目录的project\etc\ehcache.xml中
向系统目录写缓存文件的时候会比较慢,一旦jvm停止,就不再继续写入,所以在java项目下可能看到很多0kb的缓存文件,但在javaweb项目中一般就不会有事了,因为服务器启动的时间一般足够长。一般要留一些时间给jvm去写缓存。
相关文章推荐
- Hibernate+EhCache配置二级缓存
- Hibernate3一级缓存和二级缓存的理解!
- Hibernate的二级缓存
- Hibernate二级缓存问题
- hibernate 一级缓存二级缓存及查询缓存
- Hibernate二级缓存攻略
- Hibernate二级缓存的并发访问策略
- Hibernate ehcache二级缓存技术
- Hibernate--二级缓存
- Java面试原题:介绍一下hibernate的二级缓存
- 13、Hibernate的二级缓存
- Hibernate中二级缓存指的是什么?
- hibernate3.X二级缓存的使用
- hibernate二级缓存攻略
- Hibernate+EhCache配置二级缓存
- 性能优化之Hibernate4配置二级缓存
- hibernate二级缓存配置步骤、方法
- Hibernate二级缓存以及ehcache的搭建配置
- Hibernate使用二级缓存时,createSQLQuery需要注意的问题
- Spring 整合 Hibernate 时启用二级缓存实例详解