💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
Hibernate二级级缓存 上篇介绍了[Hibernate](http://blog.csdn.net/lovesummerforever/article/details/20997879)[一级缓存](http://blog.csdn.net/lovesummerforever/article/details/20997879),主要是session缓存,session生命周期结束,缓存也就结束。二级缓存相对于一级缓存来说是一个范围更广阔一些,就比你住的地方周围有多个小卖铺(session缓存),和一个大型超市,原料加工厂送货的时候送小卖铺一份的同时,必然送一份到超市。而给第二个小卖铺送一份的同时,也送给超市一份,这个超市就是我们的SessionFactory。hibernate二缓存的又称为“SessionFactory的缓存”缓存的生命周期和SessionFactory(线程安全,一个数据库对应一个,重量级)的生命周期一致,所以SessionFactory可以管理二级缓存。 下面来看session控制的二级缓存。 ### 二级缓存配置 1、需要引入第三方的jar包,hibernate的Cglib.jar。 2、在缓存的配置文件来控制缓存,我们可以拷贝hibernate已有项目中的ehcache.xml配置文件到自己的项目中。通过这个文件,我们可以对二级缓存进行设置,例如缓存的时间,缓存的代销,缓存间隔多长时间自动被清掉,缓存超时间直接缓存到磁盘指定的位置上等设置。 3、在hibernate.cfg.xml文件中加入缓存产品提供商。 ~~~ <propertyname="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> ~~~ 4、启用二级缓存,设置为true,默认是true,添加上有助于我们手动关闭和开启二级缓存。 ~~~ <propertyname="hibernate.cache.use_second_level_cache">true</property> ~~~ 5、指定哪些实体类使用二级缓存。 方法一:在对应实体的.hbm.xml文件中设置,<cacheusage="read-only"/>这样如果我们想要知道二百个映射文件哪些使用了二级缓存,就要查看二百个文件,所以我们可以把对实体加入二级缓存的策略放到hibernate.cfg.xml进行配置。也就是方法二。 方法二:处于好管理的目的我们把哪个实体使用二级缓存的配置放到hibernate.cfg.xml文件中。例如执行把student实体加入二级缓存策略。       <!--                                 指定Student使用二级缓存                           --> ~~~ <class-cacheclass="com.bjpowernode.hibernate.Student"usage="read-only"/> ~~~ 注意:缓存策略通常采用read-only和read-write 缓存原则;通常是读大于写的数据进行缓存。 ### 开启二级缓存在两个session中使用两次load()进行查询 代码如下所示。 ~~~ /** * 开启二级缓存 * * 在两个session中发load查询 */ public voidtestCache1() { Sessionsession = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Studentstudent = (Student)session.load(Student.class, 1); System.out.println("student.name=" +student.getName()); session.getTransaction().commit(); }catch(Exceptione) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } try { session = HibernateUtils.getSession(); session.beginTransaction(); Studentstudent = (Student)session.load(Student.class, 1); //不会发出查询语句,因为配置二级缓存,session可以共享二级缓存中的数据 //二级缓存是进程级的缓存 System.out.println("student.name=" +student.getName()); session.getTransaction().commit(); }catch(Exceptione) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } ~~~ 打印结果如下图所示。 ![](https://box.kancloud.cn/2016-06-21_576908fa7ec3a.jpg) 由此可知,虽然我们使用的是两个session,但第二次查询的时候没有再向数据库发出查询语句。也就是第一次查询的时候放入session的同时也放入SessionFactory缓存中一份,而第二个session再查询的时候,就直接从二级缓存中取出就可以了。 ### 开启二级缓存在两个session中使用两次get()进行查询。 代码就是把上述代码load方法改动为get方法。 运行结果如下所示。 ![](https://box.kancloud.cn/2016-06-21_576908fa7ec3a.jpg) 同load一样,对于sessionFactory级别的缓存,第二次查询时就不再向数据库发出查询sql命令。 ### 开启二级缓存,在两个session中发出load查询,采用SessionFactory管理二级缓存 代码如下所示。 ~~~ /** * 开启二级缓存 * * 在两个session中发load查询,采用SessionFactory管理二级缓存 */ public voidtestCache3() { Sessionsession = null; try { session= HibernateUtils.getSession(); session.beginTransaction(); Studentstudent = (Student)session.load(Student.class, 1); System.out.println("student.name=" +student.getName()); session.getTransaction().commit(); }catch(Exceptione) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } //管理二级缓存 (evict清除的意思) //HibernateUtils.getSessionFactory().evict(Student.class); HibernateUtils.getSessionFactory().evict(Student.class, 1); try { session= HibernateUtils.getSession(); session.beginTransaction(); Studentstudent = (Student)session.load(Student.class, 1); //会发出查询语句,因为二级缓存中的数据被清除了 System.out.println("student.name=" +student.getName()); session.getTransaction().commit(); }catch(Exceptione) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } ~~~ 显示结果如下所示。 ![](https://box.kancloud.cn/2016-06-21_576908fa981c3.jpg) 根据显示结果可知,在两个session中发出load查询,第一次放入session缓存同时放入了二级缓存sessionFactory中。在第二个session中,首先使用SessionFactory对二级缓存管理,使用evict()方法清除二级缓存,所以第二个session采用load查询时,需要重新向数据库发送sql命令。 ### 一级缓存和二级缓存交互 代码如下所示。 ~~~ public voidtestCache4() { Sessionsession = null; try { session= HibernateUtils.getSession(); session.beginTransaction(); //禁止将一级缓存中的数据放到二级缓存中。缓存模式设置为忽略。 session.setCacheMode(CacheMode.IGNORE); Studentstudent =(Student)session.load(Student.class, 1); System.out.println("student.name=" + student.getName()); session.getTransaction().commit(); }catch(Exceptione) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } try { session= HibernateUtils.getSession(); session.beginTransaction(); Studentstudent = (Student)session.load(Student.class, 1); //会发出查询语句,因为禁止了一级缓存和二级缓存的交互,一级缓存没有放到二级缓存中。 System.out.println("student.name=" +student.getName()); session.getTransaction().commit(); }catch(Exceptione) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } ~~~  显示结果如下所示。 ![](https://box.kancloud.cn/2016-06-21_576908fa981c3.jpg) 从上图可以看出,首先我们开启session的事务,然后设置了当写入session缓存中的同时不写入二级缓存,session.setCacheMode(CacheMode.IGNORE),这样第二个session再查询的时候就不能从二级缓存中找到相应的内容,仍需向数据库发出sql请求。 ### 大批量数据的添加。 当添加或更新大批量数据的时候,为了防止缓存中数据量过大,我们可以设置删除session一级缓存,如果此时开启二级缓存,那么也会同样再二级缓存中存放一份,这样的话很可能会导致缓存的溢出,所以对于大数据来说,如果放入了一级缓存中,就应该禁止再放入二级缓存中。 代码如下所示。 ~~~ /** * 大批量的数据添加 */ public voidtestCache5() { Sessionsession = null; try { session= HibernateUtils.getSession(); session.beginTransaction(); //禁止一级缓存和二级缓存交互 session.setCacheMode(CacheMode.IGNORE); for (int i=0;i<100; i++) { Studentstudent = new Student(); student.setName("张三" +i); //一级缓存放一份,二级缓存也放一份。 session.save(student); //每20条更新一次 if (i %20 == 0) { session.flush(); //清除缓存的内容 //只清除了一级缓存中的内容,没有清除一级缓存中的内容。如果数据量过大,一样溢出。 //大于大数据量来说,如果配置了一级缓存的话,就应该禁止再放入二级缓存中。 session.clear(); } } session.getTransaction().commit(); }catch(Exceptione) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } ~~~ 控制台打印sql如下图所示。 ![](https://box.kancloud.cn/2016-06-21_576908fa5c8c0.jpg) ### Hibernate二级缓存总结 从上可知,二级缓存时比一级缓存作用域更大,是在整个应用程序中。一级缓存是不能被卸载的,是必需的,不允许也无法卸载,它是事务范围的缓存。而二级缓存是可配置的,可卸载的,SessionFactory生命周期和应用程序整个过程对应,就有可能出现并发问题。 什么样的数据适合放到二级缓存中? 1、很少被修改的数据 2、不是很重要的,并允许出现偶尔的并发数据 3、不会被并发的数据 4、常量数据 什么样的数据适不合放到二级缓存中? 1、经常被修改的数据。 2、绝对不允许并发的数据。 3、与其他应用共享的数据。