目录
Mybatis缓存 2
一、MyBatis缓存介绍 2
1.导包: 2
2一级缓存代码 2
3.二级缓存代码 3
4、二级缓存补充说明 4
Hibernate 缓存 4
Hibernate 所有缓存机制详解 4
1.导包 5
2.一级缓存代码 5
3.二级缓存代码 6
4. 三级缓存代码 6
5. 一级缓存 二级缓存 三级缓存 之间的比较 7
正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持.
1. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
public static void main(String[] args) {
InputStream as = Test1.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(as);
SqlSession session = sessionFactory.openSession();
SqlSession session2 = sessionFactory.openSession();
Object obj1 = session.selectOne("user.getObjectById",1);
Object obj2 = session2.selectOne("user.getObjectById",1);
System.out.println(obj1);
System.out.println(obj2);
//session关闭
session.close();
session2.close();
}
运行结果:
public static void main(String[] args) {
InputStream as = Test1.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(as);
//开启两个不同的session
SqlSession session = sessionFactory.openSession();
SqlSession session2 = sessionFactory.openSession();
//使用二级缓存时,User类必须实现一个Serializable接口===> User implements Serializable
Object obj1 = session.selectOne("user.getObjectById",1);
session.commit();//这个地方一定要提交事务之后二级缓存才会起作用
Object obj2 = session2.selectOne("user.getObjectById",1);
System.out.println(obj1);
System.out.println(obj2);
//session关闭
session.close();
session2.close();
}
public static void main(String[] args) {
InputStream as = Test1.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(as);
//开启两个不同的session
SqlSession session = sessionFactory.openSession();
SqlSession session2 = sessionFactory.openSession();
//使用二级缓存时,User类必须实现一个Serializable接口===> User implements Serializable
Object obj1 = session.selectOne("user.getObjectById",1);
session.commit();//这个地方一定要提交事务之后二级缓存才会起作用
Object obj2 = session2.selectOne("user.getObjectById",1);
System.out.println(obj1);
System.out.println(obj2);
//session关闭
session.close();
session2.close();
}
运行结果:
1. 映射语句文件中的所有select语句将会被缓存。
2. 映射语句文件中的所有insert,update和delete语句会刷新缓存。
3. 缓存会使用Least Recently Used(LRU,最近最少使用的)算法来收回。
4. 缓存会根据指定的时间间隔来刷新。
5. 缓存会存储1024个对象
cache标签常用属性:
<cache eviction="FIFO" <!--回收策略为先进先出-->
flushInterval="60000" <!--自动刷新时间60s-->
size="512" <!--最多缓存512个引用对象-->
readOnly="true"/> <!--只读-->
hibernate提供的一级缓存
hibernate是一个线程对应一个session,一个线程可以看成一个用户。也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和线程绑定了。
hibernate一级缓存生命周期很短,和session生命周期一样,一级缓存也称session级的缓存或事务级缓存。如果tb事务提交或回滚了,我们称session就关闭了,生命周期结束了。
缓存和连接池的区别:缓 存和池都是放在内存里,实现是一样的,都是为了提高性能的。但有细微的差别,池是重量级的,里面的数据是一样的,比如一个池里放100个 Connection连接对象,这个100个都是一样的。缓存里的数据,每个都不一样。比如读取100条数据库记录放到缓存里,这100条记录都不一样。
public static void main(String[] args) {
Configuration cfg = new Configuration();
SessionFactory factory = cfg.configure("hibernate1.cfg.xml").buildSessionFactory();
Session session1= factory.openSession();
User user = (User)session1.get(User.class, 1);
//第二次查询第一次相同的数据,第二次不会发出sql语句查询数据库,而是到缓存里取数据。
User user2 = (User)session1.get(User.class, 1);
System.out.println(user);
System.out.println(user2);
//关闭sesssion 释放一级缓存
session1.close();
factory.close();
}
运行结果:
public static void main(String[] args) {
Configuration cfg = new Configuration();
SessionFactory factory = cfg.configure("hibernate2.cfg.xml").buildSessionFactory();
Session session1= factory.openSession();
Session session2= factory.openSession();
User user1 =(User)session1.load(User.class, 1);
User user2 =(User) session2.load(User.class, 1);
System.out.println(user1.getName());
System.out.println(user2.getName());
//关闭session 释放二级缓存
session1.close();
session2.close();
factory.close();
}
注:<cache usage="read-only"/>
运行结果:
可见,二级缓存是起作用了的。用get测试是同样的结果。
public static void main(String[] args) {
Configuration cfg = new Configuration();
SessionFactory factory = cfg.configure("hibernate3.cfg.xml").buildSessionFactory();
Session session1= factory.openSession();
Query query1 = session1.createQuery("FROM User");
query1.setCacheable(true);
// List list1 = query1.list();
Iterator iterate1 = query1.iterate();
Query query2 = session1.createQuery("FROM User");
query2.setCacheable(true);
// List list2 = query2.list();
Iterator iterate2 = query2.iterate();
System.out.println(iterate1);
System.out.println(iterate2);
//关闭session 释放三级缓存
session1.close();
factory.close();
}
运行结果:
一级缓存(session级的缓存):在一个session中load同一个对象2次,load时,hibernate首先在session缓存中查找对象,如果没找到就到数据库中去load。因此,在同一个session中load一个对象2次,只会发出一条sql语句。而在2个session中load同一个对象则会发送2次sql语句。
二级缓存(session的公用缓存,sessionFactory级别的缓存,jvm级缓存):hibernate支持多种二级缓存,hibernate提供了一个HashTable,用于测试,不建议运用与产品中。
二级缓存适合放什么对象呢?
①经常被访问(这个对象经常被访问,如果每次都到数据库去取,会降低效率)
②改动不大(这个对象改动不大,如果改动较大,就可能造成缓存数据跟数据库中的数据不一致)
三级缓存(查询缓存):如果要使Query使用二级缓存,则需要打开查询缓存。事实上,三级缓存是基于二级缓存的,如:list(集合),默认情况,它只会往二级缓存中存放数据,查找时不会搜索二级缓存,这是因为查询条件会随时变化。有一种情况就是2次查询的条件是一样的,这是要想使用二级缓存,就必须打开查询缓存,打开方式如:
<property name="cache.use_query_cache">true</property>
然后加上:setCachable(true)
缓存算法有:
LRU(Least Recently Used):这种算法是在每个对象中维护一个访问的时间变量,每次访问后,时间都会更新,当新的对象需要存放到缓存时,替换那个按时间排序最后的对象。
LFU(Least Frequently Used):这种算法是每个对象记录了对象访问的次数(即命中率),当新的对象需要存放到缓存时,替换那个访问次数最少的对象。
FIFO(First In First Out):这种算法是将缓存中的对象存放成一个数组,当新的对象需要存放到内存中是,替换最先存放到缓存的对象。
使用时通常在缓存配置文件中加入:MemoryStoreEvictionPolicy="LRU"。
list和iterate存放的不同之处:
①List:直接取出所有的记录将其封装成对象放到集合中。
Iterator:先取出所有记录的id(主键),当需要用到对应的id的记录时,再根据id发sql语句。②list不会主动利用session级的缓存,因此list遍历时每次会到数据库中取数据。
Iterator会利用session的缓存,Iterator每次会到缓存中找,如果缓存中没有,再到数据库中取数据。
③Iterator默认使用二级缓存
list默认往二级缓存存数据,但是查询时不使用二级缓存。