千家信息网

(20)Hibernate二级缓存

发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,1、二级缓存的知识Hibernate提供的缓存:有一级缓存、二级缓存。 目的是为了减少对数据库的访问次数,提升程序执行效率!一级缓存:基于Session的缓存,缓存内容只在当前session有效,se
千家信息网最后更新 2025年02月02日(20)Hibernate二级缓存


1、二级缓存的知识

Hibernate提供的缓存:有一级缓存二级缓存。 目的是为了减少对数据库的访问次数,提升程序执行效率!


一级缓存:基于Session的缓存,缓存内容只在当前session有效,session关闭,缓存内容失效!

特点:作用范围较小! 缓存的时间短。缓存效果不明显。


二级缓存

Hibernate提供了基于应用程序级别的缓存, 可以跨多个session,即不同的session都可以访问缓存数据。 这个缓存也叫二级缓存。

Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可;不想用,直接移除,不影响代码。

如果用户觉得hibernate提供的框架不好用,可以换其他的缓存框架或自己实现缓存框架都可以。


下面的配置位于%hibernate%/project/etc/hibernate.properties中

############################# Second-level Cache ############################### disable the second-level cache 二级缓存默认不开启,需要手动开启#hibernate.cache.use_second_level_cache false## enable the query cache#hibernate.cache.use_query_cache true 开启查询缓存## choose a cache implementation 二级缓存框架的实现#hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider#hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProviderhibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider#hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider#hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider#hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider


缓存的并发策略

     放入二级缓存的对象,只读;   非严格的读写    读写; 放入二级缓存的对象可以读、写;   (基于事务的策略)


2、使用二级缓存

二级缓存,使用步骤

1)开启二级缓存

true

2)指定缓存框架

org.hibernate.cache.HashtableCacheProvider

3)指定那些类加入二级缓存

4)测试二级缓存!


示例代码和配置

hibernate.cfg.xml

                        com.mysql.jdbc.Driver        jdbc:mysql:///test                root        root                        org.hibernate.dialect.MySQL5Dialect                                                true                                false                                update                                                                true                                org.hibernate.cache.HashtableCacheProvider                                true                                                                                                    

Department.java

package com.rk.hibernate.cache;import java.util.Set;public class Department{        private int deptId;        private String deptName;        private Set emps;        private int version;                public int getVersion()        {                return version;        }        public void setVersion(int version)        {                this.version = version;        }        public int getDeptId()        {                return deptId;        }        public void setDeptId(int deptId)        {                this.deptId = deptId;        }        public String getDeptName()        {                return deptName;        }        public void setDeptName(String deptName)        {                this.deptName = deptName;        }        public Set getEmps()        {                return emps;        }        public void setEmps(Set emps)        {                this.emps = emps;        }        @Override        public String toString()        {                return "Department [deptId=" + deptId + ", deptName=" + deptName + "]";        }        }

Department.hbm.xml

                                                                                                                                                                                                                                        

Employee.java

package com.rk.hibernate.cache;public class Employee{        private int empId;        private String empName;        private int salary;        private Department dept;        private int version;                public int getVersion()        {                return version;        }        public void setVersion(int version)        {                this.version = version;        }        public int getEmpId()        {                return empId;        }        public void setEmpId(int empId)        {                this.empId = empId;        }        public String getEmpName()        {                return empName;        }        public void setEmpName(String empName)        {                this.empName = empName;        }        public int getSalary()        {                return salary;        }        public void setSalary(int salary)        {                this.salary = salary;        }        public Department getDept()        {                return dept;        }        public void setDept(Department dept)        {                this.dept = dept;        }        @Override        public String toString()        {                return "Employee [empId=" + empId + ", empName=" + empName + ", salary=" + salary + "]";        }        }

Employee.hbm.xml

                                                                                                                                                        

App.java

package com.rk.hibernate.cache;import java.util.Iterator;import java.util.List;import java.util.Set;import org.hibernate.Query;import org.hibernate.SQLQuery;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.junit.Test;public class App{        private static SessionFactory sf;        static        {                sf = new Configuration()                                                .configure()                                                .addClass(Department.class)                                                .addClass(Employee.class)                                                .buildSessionFactory();        }                        // 1. 测试二级缓存的使用        //思路:sesion本身提供了一级缓存,它是mandatory,不能关闭        //二级缓存,是optional,通过配置文件可以开启,可以关闭。        //如果不开启二级缓存,两个session查询同一个id的数据,会发送两个SQL语句        //如果开启二级缓存,两个session查询同一个id的数据,会发送一条SQL语句        //通过开启和关闭二级缓存,来查看执行的SQL数目        @Test        public void testSecondLevelCache()        {                //第1次查询,第一个session                Session session1 = sf.openSession();                session1.beginTransaction();                            Department dept1 = (Department) session1.get(Department.class, 3);                Set emps1 = dept1.getEmps();                System.out.println(dept1);                System.out.println(emps1);                session1.getTransaction().commit();                session1.close();                                System.out.println("-------------------------------");                                //第2次查询,第二个session                Session session2 = sf.openSession();                session2.beginTransaction();                            Department dept2 = (Department) session2.get(Department.class, 3);                Set emps2 = dept2.getEmps();                System.out.println(dept2);                              System.out.println(emps2);                session2.getTransaction().commit();                session2.close();        }                        @Test        public void testQueryCache()        {                // 第1次查询,第一个session                Session session1 = sf.openSession();                session1.beginTransaction();                // HQL查询  【setCacheable  指定从二级缓存找,或者是放入二级缓存】                Query q1 = session1.createQuery("from Department").setCacheable(true);                List list1 = q1.list();                System.out.println(list1);                session1.getTransaction().commit();                session1.close();                System.out.println("-------------------------------");                // 第2次查询,第二个session                Session session2 = sf.openSession();                session2.beginTransaction();                // HQL查询  【setCacheable  指定从二级缓存找,或者是放入二级缓存】                Query q2 = session2.createQuery("from Department").setCacheable(true);                List list2 = q2.list();                System.out.println(list2);                session2.getTransaction().commit();                session2.close();        }        }


当我们开启二级缓存后,例如在上面的testSecondLevelCache()方法中,第一次从Session读取数据后,会存储在二级缓存上;第二次打开Session,程序再进行相同查询,就不需要再发送SQL语句,因为它会从二级缓存中读取数据。


有一点需要注意如果二级缓存中没有数据,第一次开启Session读取数据,并调用session.clear()方法,再读取数据,会发送两次SQL语句


  @Test        public void test1()        {                // 第1次查询,第一个session                Session session1 = sf.openSession();                session1.beginTransaction();                Department dept1 = (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: select department0_.id as id0_0_, department0_.dept_version as dept2_0_0_, department0_.name as name0_0_ from T_Department department0_ where department0_.id=?Department [deptId=2, deptName=woqu]Hibernate: select emps0_.deptId as deptId0_1_, emps0_.id as id1_, emps0_.id as id1_0_, emps0_.emp_version as emp2_1_0_, emps0_.name as name1_0_, emps0_.salary as salary1_0_, emps0_.deptId as deptId1_0_ from T_Employee emps0_ where emps0_.deptId=?[Employee [empId=3, empName=TO_T_, salary=4]]Hibernate: select department0_.id as id0_0_, department0_.dept_version as dept2_0_0_, department0_.name as name0_0_ from T_Department department0_ where department0_.id=?Department [deptId=2, deptName=woqu]Hibernate: select emps0_.deptId as deptId0_1_, emps0_.id as id1_, emps0_.id as id1_0_, emps0_.emp_version as emp2_1_0_, emps0_.name as name1_0_, emps0_.salary as salary1_0_, emps0_.deptId as deptId1_0_ from T_Employee emps0_ where emps0_.deptId=?[Employee [empId=3, empName=TO_T_, salary=4]]


如果二级缓存中已经存在数据,第二次开启Session,调用session.clear(),再读取数据,并不会发送SQL语句。

      @Test        public void test1()        {                Session session2 = sf.openSession();                session2.beginTransaction();                Department dept2 = (Department) session2.get(Department.class, 2);                System.out.println(dept2);                      System.out.println(dept2.getEmps());                                session2.getTransaction().commit();                session2.close();                                System.out.println("-------------------------------");                                                // 第1次查询,第一个session                Session session1 = sf.openSession();                session1.beginTransaction();                Department dept1 = (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: select department0_.id as id0_0_, department0_.dept_version as dept2_0_0_, department0_.name as name0_0_ from T_Department department0_ where department0_.id=?Department [deptId=2, deptName=woqu]Hibernate: select emps0_.deptId as deptId0_1_, emps0_.id as id1_, emps0_.id as id1_0_, emps0_.emp_version as emp2_1_0_, emps0_.name as name1_0_, emps0_.salary as salary1_0_, emps0_.deptId as deptId1_0_ from T_Employee emps0_ where emps0_.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]]-------------------------------









0