• Hibernate学习笔记(六) — Hibernate的二级缓存


    我们知道hibernate的一级缓存是将数据缓存到了session中从而降低与数据库的交互。那么二级缓存呢?

    一、应用场合

    比方。在12306购票时。须要选择出发地与目的地,假设每点一次都与数据库交互一次,这就非常不合适,这些地点数据在相当长的一段时间内是不会发生变化的(山东省在相当长的时间内还叫山东省),所以应该缓存起来,不是必需每次都与数据库交互,并且该类数据安全性也不是非常高。

    适合二级缓存的数据:

    在现代软件开发中。确实存在一类数据没有什么私有性,为公开的数据,数据基本上不发生变化,该数据保密性不是非常强,但又会常常被用到(比方火车票上的出发地与目的地数据)。

    注意:假设一个数据一直在改变,不适合用缓存。

    流式数据:数据时时刻刻在变的数据,比方手机应用获取手机所在地,后台的推送系统,发出一些信息。比方短信会提示你某天夜间流量超过多少。建议购买夜间流量。而这类数据适合使用strom来处理 。

    二、生命周期

    二级缓存为sessionFactory级别的缓存,其生命周期和sessionFactory是一致的,Hibernate启动后就有了.

    二级缓存在Hibernate中的位置


    所以Hibernate内部并没有实现二级缓存,而是应用第三方插件来实现二级缓存的。

    三、二级缓存的设置

    利用的是ehcache实现的二级缓存

    1.加入ehcache所需的jar包

    2.在hibernate的配置文件里进行配置


    四、二级缓存的操作

    哪些方法能够把对象放入到二级缓存中?

    get方法,list方法能够把一个或者一些对象放入到二级缓存中

    哪些方法能够把对象从二级缓存中提取出来?

    get方法,iterator方法能够提取

    注意:用的时候一定要小心使用各方法,取数据时。假设把list用成iterate会造成效率的及其减少

    五、二级缓存的存储策略


    read-only:对象仅仅要载入到二级缓存以后,就仅仅能读取,不能改动。

    read-write:对二级缓存中的对象可以进行读和写的操作

    注意:一般都设置为read-only

    缓存得到磁盘

    假设一个系统的权限特别大。这就不适合长时间的放入到二级缓存中,会导致占用内存逐渐变大。查询效率逐渐减少,这样的情况能够二级缓存移到磁盘上,可是在现代开发假设须要缓存较多。一般都是使用分布式缓存。


    測试:

    hibernate.cfg.xml

    <?

    xml version='1.0' encoding='utf-8'?

    > <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.dialect"><![CDATA[org.hibernate.dialect.MySQLDialect]]></property> <property name="hibernate.connection.driver_class"><![CDATA[com.mysql.jdbc.Driver]]></property> <property name="hibernate.connection.url"><![CDATA[jdbc:mysql:///hibernate1]]></property> <property name="hibernate.connection.username"><![CDATA[root]]></property> <property name="hibernate.connection.password"><![CDATA[qiaolezi]]></property> <property name="hibernate.c3p0.max_size">20</property> <property name="hibernate.c3p0.min_size">10</property> <property name="hibernate.c3p0.max_statements">10</property> <property name="hibernate.c3p0.acquire_increment">5</property> <property name="hibernate.c3p0.timeout">3000</property> <!-- 二级缓存供应商 --> <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property> <!-- 开启二级缓存 --> <property name="cache.use_second_level_cache">true</property> <!-- 开启二级缓存的统计机制 --> <property name="generate_statistics">true</property> <property name="hbm2ddl.auto">update</property> <property name="show_sql">true</property> <property name="current_session_context_class">thread</property> <property name="format_sql">true</property> <mapping resource="cn/cil/domain/Classes.hbm.xml" /> <mapping resource="cn/cil/domain/Student.hbm.xml" /> </session-factory> </hibernate-configuration>

    Classes

    public class Classes implements Serializable{
    
    	private Long cid;
    	private String name;
    	private Set<Student> students;
    }
    Classes.hbm.xml

    <class name="Classes" table="CLASSES">
    		<cache usage="read-write"/><!-- 仅仅读 -->
    		<id name="cid">
    			<generator class="native"></generator>
    		</id>
    		<property name="name"></property>
    		<set name="students" cascade="save-update" inverse="true">
    			<cache usage="read-only"/><!-- 设置集合的二级缓存 -->
    		<!-- key:外键,告诉hibernate通过cid来建立classes与student的关系 -->
    			<key column="cid"></key>
    			<one-to-many class="Student"/>
    		</set>
    	</class>

    Student

    public class Student implements Serializable{
    
    	private Long sid;
    	private String name;
    	private Classes classes;
    }
    Student.hbm.xml

    <class name="Student" table="STUDENT">
    		<id name="sid">
    			<generator class="native"></generator>
    		</id>
    		<property name="name"></property>
    	
    		<many-to-one cascade="save-update" name="classes" column="cid" class="Classes">
    		</many-to-one>
    	</class>

    測试类

    public class SessionFactoryCacheTest {
    
    	private Session session;
    	private Transaction transaction;
    	private SessionFactory sessionFactory;
    	
    	/**
    	 * 測试get,在session关闭后,再次请求,不发出sql
    	 * 该方法在取数据时,先从一级缓存中找,假设二级缓存开启了,接下来就会从二级缓存中,都没有,则查数据库
    	 * 在DefaultLoadEventListener.class中能够清晰的看到
    	 * 440行: 从一级缓存,459 行: 从二级缓存,477行: 从数据库
    	 * 
    	 * get能够把对象放入二级缓存,也能够从二级缓存中取数据
    	 */
    	@Test
    	public void testGet(){
    		
    		sessionFactory = HibernateUtils.getSessionFactory();
    		 session = HibernateUtils.openSession();
    		Classes classes = (Classes) session.get(Classes.class, 1L);
    		System.out.println(sessionFactory.getStatistics()
    				.getEntityLoadCount());//1
    		session.close();
    		session = HibernateUtils.openSession();
    	    classes = (Classes) session.get(Classes.class, 1L);//不发出sql
    		session.close();
    	}
    	/**
    	 * Hibernate提供了二级缓存的统计机制
    	 * save不能把对象存入二级缓存
    	 */
    	@Test
    	public void testSave(){
    		sessionFactory = HibernateUtils.getSessionFactory();
    		session = HibernateUtils.openSession();
    		transaction = session.beginTransaction();
    		Classes classes = new Classes();
    		classes.setName("a");
    		session.save(classes);
    		System.out.println(sessionFactory.getStatistics()
    				.getEntityLoadCount());//0
    		transaction.commit();
    		session.close();
    	}
    	
    	/**
    	 * session.update不操作二级缓存
    	 */
    	@Test
    	public void testUpdate(){
    		sessionFactory = HibernateUtils.getSessionFactory();
    		session = sessionFactory.openSession();
    		Transaction transaction = session.beginTransaction();
    		Classes classes = new Classes();
    		classes.setCid(3L);
    		classes.setName("afds");
    		session.update(classes);
    		System.out.println(sessionFactory.getStatistics()
    				.getEntityInsertCount());//0
    		transaction.commit();//会报错,可是不影响,设置为<cache usage="read-write">,假设集合也设置了二级缓存,那集合也要设置为相同
    		session.close();
    	}
    	
    	/**
    	 * HQL中的list,能够把对象放入到二级缓存,可是不能从二级缓存取数据
    	 */
    	@Test
    	public void testQueryList(){
    		sessionFactory = HibernateUtils.getSessionFactory();
    		session = sessionFactory.openSession();
    		
    		session.createQuery("from Classes").list();
    		System.out.println(sessionFactory.getStatistics()
    				.getEntityLoadCount());//不是0
    		session.close();
    		session = sessionFactory.openSession();
    		session.createQuery("from Classes").list();//发出sql,由于getEntityLoadCount不为0,所以list()能够把对象放入二级缓存,可是不能从二级缓存中取对象
    		session.close();
    	}
    	
    	/**
    	 *  iterator,能够从二级缓存中取数据
    	 *  iterate方法的查询策略:
    	 *  	先查找该表中全部的id值
    	 *  	再依据id值从二级缓存中查找对象,假设有,则利用二级缓存,
    	 *  						     假设没有,则依据id查询全部属性的值
    	 */
    	
    	@Test
    	public void testQueryIterate(){
    		sessionFactory = HibernateUtils.getSessionFactory();
    		session = sessionFactory.openSession();
    		session.createQuery("from Classes").list();
    		
    		System.out.println(sessionFactory.getStatistics()
    				.getEntityLoadCount());//不是0
    		session.close();
    		session = sessionFactory.openSession();
    		Iterator<Classes> iterator = session.createQuery("from Classes").iterate();
    		while (iterator.hasNext()) {
    			Classes classes = (Classes) iterator.next();
    			System.out.println(classes.getName());
    		}
    		
    		session.close();
    	}
    	
    	/**
    	 * 集合的二级缓存,须要在hbm.xml文件里进行对应的设置
    	 * 集合有一级缓存也有二级缓存
    	 */
    	@Test
    	public void testCollection(){
    		sessionFactory = HibernateUtils.getSessionFactory();
    		session = sessionFactory.openSession();
    		
    		Classes classes = (Classes) session.get(Classes.class, 1L);
    		Set<Student> students = classes.getStudents();
    		for(Student student : students){
    			System.out.println(student.getName());
    		}
    		System.out.println(sessionFactory.getStatistics()
    				.getCollectionLoadCount());//1
    		session.close();
    	}
    	
    	
    	/**
    	 * 二级缓存 到 磁盘
    	 */
    	@Test
    	public void testCacheDisk(){
    		sessionFactory = HibernateUtils.getSessionFactory();
    		session = sessionFactory.openSession();
    		
    		session.createQuery("from Classes").list();
    		try {
    			Thread.sleep(2000L);//停一会,否则写不进去数据
    		} catch (Exception e) {
    			
    			e.printStackTrace();
    		}
    		session.close();
    	}
    }
    

    二级缓存企业应用的不多,实在有些鸡肋

  • 相关阅读:
    contextMenu,右键菜单
    hashchange
    web攻击日志分析之新手指南
    工匠人生
    数学有卵用之通信篇
    精英主义(一)
    flaskbb部署笔记
    深入分析一波,你们说的云安全到底是什么鬼?
    Gh0st与云安全
    困境与突破
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/6848838.html
Copyright © 2020-2023  润新知