(20)Hibernate二级缓存
1、二级缓存的知识
Hibernate提供的缓存:有一级缓存、二级缓存。 目的是为了减少对数据库的访问次数,提升程序执行效率!
一级缓存:基于Session的缓存,缓存内容只在当前session有效,session关闭,缓存内容失效!
特点:作用范围较小! 缓存的时间短。缓存效果不明显。
二级缓存:
Hibernate提供了基于应用程序级别的缓存, 可以跨多个session,即不同的session都可以访问缓存数据。 这个缓存也叫二级缓存。
Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可;不想用,直接移除,不影响代码。
如果用户觉得hibernate提供的框架不好用,可以换其他的缓存框架或自己实现缓存框架都可以。
下面的配置位于%hibernate%/project/etc/hibernate.properties中
#############################Second-levelCache###############################disablethesecond-levelcache二级缓存默认不开启,需要手动开启#hibernate.cache.use_second_level_cachefalse##enablethequerycache#hibernate.cache.use_query_cachetrue开启查询缓存##chooseacacheimplementation二级缓存框架的实现#hibernate.cache.provider_classorg.hibernate.cache.EhCacheProvider#hibernate.cache.provider_classorg.hibernate.cache.EmptyCacheProviderhibernate.cache.provider_classorg.hibernate.cache.HashtableCacheProvider#hibernate.cache.provider_classorg.hibernate.cache.TreeCacheProvider#hibernate.cache.provider_classorg.hibernate.cache.OSCacheProvider#hibernate.cache.provider_classorg.hibernate.cache.SwarmCacheProvider
缓存的并发策略
<class-cacheusage="read-only"/>放入二级缓存的对象,只读;<class-cacheusage="nonstrict-read-write"/>非严格的读写<class-cacheusage="read-write"/>读写;放入二级缓存的对象可以读、写;<class-cacheusage="transactional"/>(基于事务的策略)
2、使用二级缓存
二级缓存,使用步骤
1)开启二级缓存
<propertyname="hibernate.cache.use_second_level_cache">true</property>
2)指定缓存框架
<propertyname="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
3)指定那些类加入二级缓存
<!--指定哪一些类,需要加入二级缓存--><class-cacheusage="read-write"class="com.rk.hibernate.cache.Department"/><class-cacheusage="read-write"class="com.rk.hibernate.cache.Employee"/><!--集合缓存[集合缓存的元素对象,也加加入二级缓存]--><collection-cacheusage="read-write"collection="com.rk.hibernate.cache.Department.emps"/>
4)测试二级缓存!
示例代码和配置
hibernate.cfg.xml
<!DOCTYPEhibernate-configurationPUBLIC"-//Hibernate/HibernateConfigurationDTD3.0//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration><!--通常,一个session-factory节点代表一个数据库--><session-factory><!--1.数据库连接配置--><propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property><propertyname="hibernate.connection.url">jdbc:mysql:///test</property><propertyname="hibernate.connection.username">root</property><propertyname="hibernate.connection.password">root</property><!--数据库方言配置,hibernate在运行的时候,会根据不同的方言生成符合当前数据库语法的sql--><propertyname="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property><!--2.其他相关配置--><!--2.1显示hibernate在运行时候执行的sql语句--><propertyname="hibernate.show_sql">true</property><!--2.2格式化sql--><propertyname="hibernate.format_sql">false</property><!--2.3自动建表--><propertyname="hibernate.hbm2ddl.auto">update</property><!--******************【二级缓存配置】******************--><!--a.开启二级缓存--><propertyname="hibernate.cache.use_second_level_cache">true</property><!--b.指定使用哪一个缓存框架(默认提供的)--><propertyname="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property><!--开启查询缓存--><propertyname="hibernate.cache.use_query_cache">true</property><!--c.指定哪一些类,需要加入二级缓存--><class-cacheusage="read-write"class="com.rk.hibernate.cache.Department"/><class-cacheusage="read-write"class="com.rk.hibernate.cache.Employee"/><!--集合缓存[集合缓存的元素对象,也加加入二级缓存]--><collection-cacheusage="read-write"collection="com.rk.hibernate.cache.Department.emps"/></session-factory></hibernate-configuration>
Department.java
packagecom.rk.hibernate.cache;importjava.util.Set;publicclassDepartment{privateintdeptId;privateStringdeptName;privateSet<Employee>emps;privateintversion;publicintgetVersion(){returnversion;}publicvoidsetVersion(intversion){this.version=version;}publicintgetDeptId(){returndeptId;}publicvoidsetDeptId(intdeptId){this.deptId=deptId;}publicStringgetDeptName(){returndeptName;}publicvoidsetDeptName(StringdeptName){this.deptName=deptName;}publicSet<Employee>getEmps(){returnemps;}publicvoidsetEmps(Set<Employee>emps){this.emps=emps;}@OverridepublicStringtoString(){return"Department[deptId="+deptId+",deptName="+deptName+"]";}}
Department.hbm.xml
<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mappingpackage="com.rk.hibernate.cache"auto-import="true"><classname="Department"table="T_Department"><!--<cacheusage="read-only"/>--><idname="deptId"column="id"><generatorclass="native"></generator></id><versionname="version"column="dept_version"></version><propertyname="deptName"column="name"type="string"></property><setname="emps"table="T_Employee"><!--<cacheusage="read-only"/>--><keycolumn="deptId"></key><one-to-manyclass="Employee"/></set></class></hibernate-mapping>
Employee.java
packagecom.rk.hibernate.cache;publicclassEmployee{privateintempId;privateStringempName;privateintsalary;privateDepartmentdept;privateintversion;publicintgetVersion(){returnversion;}publicvoidsetVersion(intversion){this.version=version;}publicintgetEmpId(){returnempId;}publicvoidsetEmpId(intempId){this.empId=empId;}publicStringgetEmpName(){returnempName;}publicvoidsetEmpName(StringempName){this.empName=empName;}publicintgetSalary(){returnsalary;}publicvoidsetSalary(intsalary){this.salary=salary;}publicDepartmentgetDept(){returndept;}publicvoidsetDept(Departmentdept){this.dept=dept;}@OverridepublicStringtoString(){return"Employee[empId="+empId+",empName="+empName+",salary="+salary+"]";}}
Employee.hbm.xml
<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mappingpackage="com.rk.hibernate.cache"auto-import="true"><classname="Employee"table="T_Employee"><!--<cacheusage="read-only"/>--><idname="empId"column="id"><generatorclass="native"></generator></id><versionname="version"column="emp_version"></version><propertyname="empName"column="name"type="string"></property><propertyname="salary"column="salary"type="int"></property><many-to-onename="dept"column="deptId"class="Department"></many-to-one></class></hibernate-mapping>
App.java
packagecom.rk.hibernate.cache;importjava.util.Iterator;importjava.util.List;importjava.util.Set;importorg.hibernate.Query;importorg.hibernate.SQLQuery;importorg.hibernate.Session;importorg.hibernate.SessionFactory;importorg.hibernate.cfg.Configuration;importorg.junit.Test;publicclassApp{privatestaticSessionFactorysf;static{sf=newConfiguration().configure().addClass(Department.class).addClass(Employee.class).buildSessionFactory();}//1.测试二级缓存的使用//思路:sesion本身提供了一级缓存,它是mandatory,不能关闭//二级缓存,是optional,通过配置文件可以开启,可以关闭。//如果不开启二级缓存,两个session查询同一个id的数据,会发送两个SQL语句//如果开启二级缓存,两个session查询同一个id的数据,会发送一条SQL语句//通过开启和关闭二级缓存,来查看执行的SQL数目@TestpublicvoidtestSecondLevelCache(){//第1次查询,第一个sessionSessionsession1=sf.openSession();session1.beginTransaction();Departmentdept1=(Department)session1.get(Department.class,3);Set<Employee>emps1=dept1.getEmps();System.out.println(dept1);System.out.println(emps1);session1.getTransaction().commit();session1.close();System.out.println("-------------------------------");//第2次查询,第二个sessionSessionsession2=sf.openSession();session2.beginTransaction();Departmentdept2=(Department)session2.get(Department.class,3);Set<Employee>emps2=dept2.getEmps();System.out.println(dept2);System.out.println(emps2);session2.getTransaction().commit();session2.close();}@TestpublicvoidtestQueryCache(){//第1次查询,第一个sessionSessionsession1=sf.openSession();session1.beginTransaction();//HQL查询【setCacheable指定从二级缓存找,或者是放入二级缓存】Queryq1=session1.createQuery("fromDepartment").setCacheable(true);List<Department>list1=q1.list();System.out.println(list1);session1.getTransaction().commit();session1.close();System.out.println("-------------------------------");//第2次查询,第二个sessionSessionsession2=sf.openSession();session2.beginTransaction();//HQL查询【setCacheable指定从二级缓存找,或者是放入二级缓存】Queryq2=session2.createQuery("fromDepartment").setCacheable(true);List<Department>list2=q2.list();System.out.println(list2);session2.getTransaction().commit();session2.close();}}
当我们开启二级缓存后,例如在上面的testSecondLevelCache()方法中,第一次从Session读取数据后,会存储在二级缓存上;第二次打开Session,程序再进行相同查询,就不需要再发送SQL语句,因为它会从二级缓存中读取数据。
有一点需要注意:如果二级缓存中没有数据,第一次开启Session读取数据,并调用session.clear()方法,再读取数据,会发送两次SQL语句。
@Testpublicvoidtest1(){//第1次查询,第一个sessionSessionsession1=sf.openSession();session1.beginTransaction();Departmentdept1=(Department)session1.get(Department.class,2);System.out.println(dept1);System.out.println(dept1.getEmps());session1.clear();dept1=(Department)session1.get(Department.class,2);System.out.println(dept1);System.out.println(dept1.getEmps());session1.getTransaction().commit();session1.close();}
结果如下:
Hibernate:selectdepartment0_.idasid0_0_,department0_.dept_versionasdept2_0_0_,department0_.nameasname0_0_fromT_Departmentdepartment0_wheredepartment0_.id=?Department[deptId=2,deptName=woqu]Hibernate:selectemps0_.deptIdasdeptId0_1_,emps0_.idasid1_,emps0_.idasid1_0_,emps0_.emp_versionasemp2_1_0_,emps0_.nameasname1_0_,emps0_.salaryassalary1_0_,emps0_.deptIdasdeptId1_0_fromT_Employeeemps0_whereemps0_.deptId=?[Employee[empId=3,empName=TO_T_,salary=4]]Hibernate:selectdepartment0_.idasid0_0_,department0_.dept_versionasdept2_0_0_,department0_.nameasname0_0_fromT_Departmentdepartment0_wheredepartment0_.id=?Department[deptId=2,deptName=woqu]Hibernate:selectemps0_.deptIdasdeptId0_1_,emps0_.idasid1_,emps0_.idasid1_0_,emps0_.emp_versionasemp2_1_0_,emps0_.nameasname1_0_,emps0_.salaryassalary1_0_,emps0_.deptIdasdeptId1_0_fromT_Employeeemps0_whereemps0_.deptId=?[Employee[empId=3,empName=TO_T_,salary=4]]
如果二级缓存中已经存在数据,第二次开启Session,调用session.clear(),再读取数据,并不会发送SQL语句。
@Testpublicvoidtest1(){Sessionsession2=sf.openSession();session2.beginTransaction();Departmentdept2=(Department)session2.get(Department.class,2);System.out.println(dept2);System.out.println(dept2.getEmps());session2.getTransaction().commit();session2.close();System.out.println("-------------------------------");//第1次查询,第一个sessionSessionsession1=sf.openSession();session1.beginTransaction();Departmentdept1=(Department)session1.get(Department.class,2);System.out.println(dept1);System.out.println(dept1.getEmps());session1.clear();dept1=(Department)session1.get(Department.class,2);System.out.println(dept1);System.out.println(dept1.getEmps());session1.getTransaction().commit();session1.close();System.out.println("-------------------------------");}
结果如下:
Hibernate:selectdepartment0_.idasid0_0_,department0_.dept_versionasdept2_0_0_,department0_.nameasname0_0_fromT_Departmentdepartment0_wheredepartment0_.id=?Department[deptId=2,deptName=woqu]Hibernate:selectemps0_.deptIdasdeptId0_1_,emps0_.idasid1_,emps0_.idasid1_0_,emps0_.emp_versionasemp2_1_0_,emps0_.nameasname1_0_,emps0_.salaryassalary1_0_,emps0_.deptIdasdeptId1_0_fromT_Employeeemps0_whereemps0_.deptId=?[Employee[empId=3,empName=TO_T_,salary=4]]-------------------------------Department[deptId=2,deptName=woqu][Employee[empId=3,empName=TO_T_,salary=4]]Department[deptId=2,deptName=woqu][Employee[empId=3,empName=TO_T_,salary=4]]-------------------------------
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。