首页 > 代码库 > Hibernate的时间戳缓存区域

Hibernate的时间戳缓存区域

时间戳:一个详细到秒的时间点,就是一个时分秒的字符串

时间戳缓存区域存放了对于查询结果相关的表进行插入, 更新或删除操作的时间戳.
Hibernate 通过时间戳缓存区域来判断被缓存的查询结果是否过期,
其运行过程如下: (T1和T2没有规定谁先谁后的,是程序需要操作的)
T1 时刻执行查询操作(就例如一个客户1在客户端进行一次查询), 把查询结果存放在 QueryCache 区域, 记录该区域的时间戳为 T1
T2 时刻对查询结果相关的表进行更新操作(管理员在某个时间对客户查询的表进行了更新操作), Hibernate 把 T2 时刻存放在 UpdateTimestampCache 区域.
T3 时刻执行查询结果前(又有另外一个客户执行了客户1同样的查询语句), 先比较 QueryCache 区域的时间戳(T1)和 UpdateTimestampCache 区域的时间戳(T2),
   若 T2 >T1, 那么就丢弃原先存放在 QueryCache 区域的查询结果, 重新到数据库中查询数据, 再把结果存放到 QueryCache 区域;
   若 T2 < T1, 直接从 QueryCache 中获得查询结果
这就是时间戳的缓存原理:

所有的二级缓存的查询缓存遵循时间戳缓存策略,对象二级缓存和集合二级缓存不支持此策略,

例如咋们对某个对象进行了二级缓存,但同时又做了对象对应表的更新操作
测试代码如下

@Test    public void testHibernateSecondLevelCache(){        Employee employee = (Employee) session.get(Employee.class, 15);        System.out.println(employee.getName());                 transaction.commit();        session.close();        System.out.println("--------------------------------------");        session = sessionFactory.openSession();        transaction = session.beginTransaction();        Employee employee2=new Employee();                employee2.setEmail("sdkfjsd@qq.com");        employee2.setName("jeremy");        employee2.setSalary(8000F);        session.save(employee2);                        Employee employee3 = (Employee) session.get(Employee.class, 15);        System.out.println(employee3.getName());     }

我已经设置了二级缓存了,如果二级缓存没有失效我这里应该是发送了一条select语句和一条insert语句,运行结果也是那样

Hibernate:     select        employee0_.ID as ID1_1_0_,        employee0_.NAME as NAME2_1_0_,        employee0_.SALARY as SALARY3_1_0_,        employee0_.EMAIL as EMAIL4_1_0_,        employee0_.DEPT_ID as DEPT_ID5_1_0_     from        GG_EMPLOYEE employee0_     where        employee0_.ID=?AA--------------------------------------Hibernate:     insert     into        GG_EMPLOYEE        (NAME, SALARY, EMAIL, DEPT_ID)     values        (?, ?, ?, ?)AA

也就证明了对象二级缓存不支持时间戳缓存策略。collection也是这样,

而查询缓存就支持这个策略:

代码如下:

  例如运行下面测试代码:
@Test    public void testQueryCache(){        Query query = session.createQuery("FROM Employee e where e.id=1");        query.setCacheable(true);                List<Employee> emps = query.list();        System.out.println(emps.size());        System.out.println(emps.iterator().next().getClass());                Employee employee=new Employee();                employee.setEmail("sdkfjsd@qq.com");        employee.setName("jeremy");        employee.setSalary(8000F);        session.save(employee);                emps = query.list();        System.out.println(emps.size());                //Criteria criteria = session.createCriteria(Employee.class);        //criteria.setCacheable(true);    }

运行结果:

Hibernate:     select        employee0_.ID as ID1_1_,        employee0_.NAME as NAME2_1_,        employee0_.SALARY as SALARY3_1_,        employee0_.EMAIL as EMAIL4_1_,        employee0_.DEPT_ID as DEPT_ID5_1_     from        GG_EMPLOYEE employee0_     where        employee0_.ID=101class com.atguigu.hibernate.entities.EmployeeHibernate:     insert     into        GG_EMPLOYEE        (NAME, SALARY, EMAIL, DEPT_ID)     values        (?, ?, ?, ?)Hibernate:     select        employee0_.ID as ID1_1_,        employee0_.NAME as NAME2_1_,        employee0_.SALARY as SALARY3_1_,        employee0_.EMAIL as EMAIL4_1_,        employee0_.DEPT_ID as DEPT_ID5_1_     from        GG_EMPLOYEE employee0_     where        employee0_.ID=101


我在进行了第一次HQL查询后又对了数据表进行了增加操作了,此时的数据表已经发生了改变了,此时查询缓存被关闭了(就算更新操作对我HQL语句查询的结果没影响,但是查询缓存还是被关闭了)

如果查询缓存没有被关闭,那已是发送一条select语句和一条insert语句,但是现在是发送了两条select语句,一条insert语句 ,所以证明了,当查询缓存相关的表更新后,
查询缓存会自动关闭,这一点需要记住

Hibernate的时间戳缓存区域