Hibernate 缓存机制
2017-03-19 12:01
363 查看
Hibernate中缓存主要分为–一级缓存 和二级缓存。
一级缓存:又称为Session缓存,是系统内置且不可卸载,同时属于事务范畴缓存,即事务结束时,Session缓存的生命周期结束;
二级缓存:又称SessionFactory缓存,是系统内置可供选择的缓存,默认不开启,属于应用范围内的缓存,即应用结束时,SessionFactory缓存生命周期结束。
由于hibernate缓存机制存在不同步问题(可以刷新同步但失去效率),因此一般开启二级缓存的实体类需要满足下面条件:
不经常修改的实体类
常量
很少并发或不允许并发的操作(财务数据)等。
下面以实例来说明缓存问题:
一级缓存:
运行结果是:
第一次获取======:张三
result=1
第二次获取======:张三
从结果可以看出 第一获取员工姓名的时候输出,然后把
4000
员工从数据库中删除(数据库没有这条记录),但是在此获取该员工姓名的时候发现还可以获取,说明Session中的缓存并没有更新与数据库同步(区别于session.delete(obj)会更新session缓存)。同理Update操作也存在这个问题。解决这个问题的方法就是刷新Session缓存(session.refresh()),用不用刷新存在数据库执行语句的不同,不刷新,则是先用Select查询数据库,输出员工姓名,然后删除数据库记录(返回变动记录数1),最后直接从session缓存中获取对象输出;而用刷新则是从在删除记录后,重新Select查询数据库,所以结果会是最新的(抛异常对象实体类不存在)。从中也会发现get(load 以及使用查询语句查询包含相同的对象即使数据库数据更新 返回的该对象也是Session中的对象记录 除非用refresh)函数是先从session缓存中查询如果没有则直接从数据库查询。session生命周期结束的时候,再次查询获取为数据库中的数据。
二级缓存:
上面代码中如果没有开启二级缓存,则系统会执行两个查询语句,即当事物提交就会执行操作语句,但session的缓存伴随session关闭而结束。
如果事物提交session未关闭则还是会用session缓存,而重新建立session则是新的session;当启用二级缓存,即使事物提交,session关闭,二级缓存存在的对象也只会查询一次。
上面的代码中即使第一次根据部门查询该部门所有员工,但第二次查询需要把下面的所有员工根据员工id一条一条查询效率非常慢,这主要是因为在部门实体类中有一个Setemployees,即使设置了其集合缓存,但没有设置其父类Employees缓存,则系统是不会二级缓存该对象的完整版,只能通过OID查询,所以UI好的方法是连同Employee是一块设置缓存。
结果:
一级缓存:又称为Session缓存,是系统内置且不可卸载,同时属于事务范畴缓存,即事务结束时,Session缓存的生命周期结束;
二级缓存:又称SessionFactory缓存,是系统内置可供选择的缓存,默认不开启,属于应用范围内的缓存,即应用结束时,SessionFactory缓存生命周期结束。
由于hibernate缓存机制存在不同步问题(可以刷新同步但失去效率),因此一般开启二级缓存的实体类需要满足下面条件:
不经常修改的实体类
常量
很少并发或不允许并发的操作(财务数据)等。
下面以实例来说明缓存问题:
一级缓存:
Session session=sessionFactory.openSession(); session.beginTransaction(); String hql=null; Employees employee=(Employees)session.get(Employees.class, 14); System.out.println("第一次获取======:"+employee.getName()); //hql="UPDATE Employees e SET e.name=? where id=14"; hql="delete from Employees as e where e.id=14"; int result =session.createQuery(hql).executeUpdate(); // int result= session.createQuery(hql).setParameter(0, "剑锋").executeUpdate(); System.out.println("result="+result); //session.refresh(employee); System.out.println("第二次获取======:"+employee.getName()); session.getTransaction().commit(); session.close();
运行结果是:
第一次获取======:张三
result=1
第二次获取======:张三
从结果可以看出 第一获取员工姓名的时候输出,然后把
4000
员工从数据库中删除(数据库没有这条记录),但是在此获取该员工姓名的时候发现还可以获取,说明Session中的缓存并没有更新与数据库同步(区别于session.delete(obj)会更新session缓存)。同理Update操作也存在这个问题。解决这个问题的方法就是刷新Session缓存(session.refresh()),用不用刷新存在数据库执行语句的不同,不刷新,则是先用Select查询数据库,输出员工姓名,然后删除数据库记录(返回变动记录数1),最后直接从session缓存中获取对象输出;而用刷新则是从在删除记录后,重新Select查询数据库,所以结果会是最新的(抛异常对象实体类不存在)。从中也会发现get(load 以及使用查询语句查询包含相同的对象即使数据库数据更新 返回的该对象也是Session中的对象记录 除非用refresh)函数是先从session缓存中查询如果没有则直接从数据库查询。session生命周期结束的时候,再次查询获取为数据库中的数据。
二级缓存:
Session session=sessionFactory.openSession(); session.beginTransaction(); Employees employee=(Employees)session.get(Employees.class, 1); System.out.println(employee); session.getTransaction().commit(); session.close(); //===========================第二个session Session session2=sessionFactory.openSession(); session2.beginTransaction(); Employees employee2=(Employees)session2.get(Employees.class, 1); System.out.println(employee2); session2.getTransaction().commit(); session2.close();
上面代码中如果没有开启二级缓存,则系统会执行两个查询语句,即当事物提交就会执行操作语句,但session的缓存伴随session关闭而结束。
如果事物提交session未关闭则还是会用session缓存,而重新建立session则是新的session;当启用二级缓存,即使事物提交,session关闭,二级缓存存在的对象也只会查询一次。
<!--缓存提供商 这样就打开了缓存设置--> <property name="cache.provider_class"> org.hibernate.cache.HashtableCacheProvider</property> <!--开启查询缓存 必须放在实体类前--> <property name="cache.use_query_cache">true</property> <!--指定二级缓存指定类--> <class-cache usage="read-write" class="com.liurui.www_second_cache.Department"></class-cache> <!--<class-cache usage="read-write" class="com.liurui.www_second_cache.Employees"></class-cache>--> <!--集合缓存--> <collection-cache usage="read-write" collection="com.liurui.www_second_cache.Department.employees"></collection-cache>
Session session=sessionFactory.openSession(); session.beginTransaction(); Department department=(Department)session.get(Department.class, 1); System.out.println(department); System.out.println(department.getEmployees()); session.getTransaction().commit(); session.close(); //===================即集合employees使用缓存 则其实体类Employee是也必须使用缓存 否则session二级缓存是不会缓存的 Session session2=sessionFactory.openSession(); session2.beginTransaction(); Department department2=(Department)session2.get(Department.class, 1); System.out.println(department2); System.out.println(department2.getEmployees()); session2.getTransaction().commit(); session2.close();
上面的代码中即使第一次根据部门查询该部门所有员工,但第二次查询需要把下面的所有员工根据员工id一条一条查询效率非常慢,这主要是因为在部门实体类中有一个Setemployees,即使设置了其集合缓存,但没有设置其父类Employees缓存,则系统是不会二级缓存该对象的完整版,只能通过OID查询,所以UI好的方法是连同Employee是一块设置缓存。
//===================query 默认是不用二级缓存的 每次查询到会放进缓存 但再次查询不会用 缓存只是get load(一级 二级 缓存 必须使用oid) Session session=sessionFactory.openSession(); session.beginTransaction(); List<Employees> list=session.createQuery("from Employees e where e.id<10").list(); System.out.println(list); session.getTransaction().commit(); session.close(); //=================== Session session2=sessionFactory.openSession(); session2.beginTransaction(); List<Employees> list2=session2.createQuery("from Employees e where e.id<10").list(); System.out.println(list2); session2.getTransaction().commit(); session2.close();
//===================query 使用缓存则是用OID 一个一个查询 就可以使用缓存 效率不高 Session session=sessionFactory.openSession(); session.beginTransaction(); Iterator<Employees> iterator=session.createQuery("from Employees e where e.id<10").iterate(); while(iterator.hasNext()){ Employees e=iterator.next(); System.out.println(e); } session.getTransaction().commit(); session.close(); //=================== Session session2=sessionFactory.openSession(); session2.beginTransaction(); Iterator<Employees> iterator2=session2.createQuery("from Employees e where e.id<10").iterate(); while(iterator2.hasNext()){ Employees e=iterator2.next(); System.out.println(e); } session2.getTransaction().commit(); session2.close();
结果:
Hibernate: select employees0_.id as col_0_0_ from employee employees0_ where employees0_.id<10 Hibernate: select employees0_.id as id1_0_, employees0_.name as name1_0_, employees0_.departmentId as departme3_1_0_ from employee employees0_ where employees0_.id=? [ id=1, name=飘7雪] Hibernate: select employees0_.id as id1_0_, employees0_.name as name1_0_, employees0_.departmentId as departme3_1_0_ from employee employees0_ where employees0_.id=? [ id=2, name=李1哥] Hibernate: select employees0_.id as id1_0_, employees0_.name as name1_0_, employees0_.departmentId as departme3_1_0_ from employee employees0_ where employees0_.id=? [ id=3, name=李2哥] Hibernate: select employees0_.id as id1_0_, employees0_.name as name1_0_, employees0_.departmentId as departme3_1_0_ from employee employees0_ where employees0_.id=? [ id=4, name=李3哥] Hibernate: select employees0_.id as id1_0_, employees0_.name as name1_0_, employees0_.departmentId as departme3_1_0_ from employee employees0_ where employees0_.id=? [ id=5, name=李4哥] Hibernate: select employees0_.id as id1_0_, employees0_.name as name1_0_, employees0_.departmentId as departme3_1_0_ from employee employees0_ where employees0_.id=? [ id=6, name=李5哥] Hibernate: select empl ba89 oyees0_.id as id1_0_, employees0_.name as name1_0_, employees0_.departmentId as departme3_1_0_ from employee employees0_ where employees0_.id=? [ id=7, name=李6哥] Hibernate: select employees0_.id as id1_0_, employees0_.name as name1_0_, employees0_.departmentId as departme3_1_0_ from employee employees0_ where employees0_.id=? [ id=9, name=西门] Hibernate: select employees0_.id as col_0_0_ from employee employees0_ where employees0_.id<10 [ id=1, name=飘7雪] [ id=2, name=李1哥] [ id=3, name=李2哥] [ id=4, name=李3哥] [ id=5, name=李4哥] [ id=6, name=李5哥] [ id=7, name=李6哥] [ id=9, name=西门]
query开启二级缓存 <property name="cache.use_query_cache">true</property> ............ //===================query 开启缓存 在主配置文件中这种缓存是一次结果对应一个查询语句作为key值存储,所以查询语句必须完全相同才可以使用 Session session=sessionFactory.openSession(); session.beginTransaction(); List<Employees> list=session.createQuery("from Employees e where e.id<10").setCacheable(true).list(); System.out.println(list); session.getTransaction().commit(); session.close(); //===================必须查询条件才可以用缓存 缓存外的数据记录另外查询 Session session2=sessionFactory.openSession(); session2.beginTransaction(); List<Employees> list2=session2.createQuery("from Employees e where e.id<7").setCacheable(true).list(); System.out.println(list2); session2.getTransaction().commit(); session2.close();
//===================query 开启缓存 在主配置文件中 Session session=sessionFactory.openSession(); session.beginTransaction(); Employees employee1=(Employees)session.get(Employees.class, 1); System.out.println(employee1.getName()); //更新数据库 session.createQuery("update Employees e set e.name=? where id=?").setParameter(0, "测试6").setParameter(1, 1).executeUpdate(); System.out.println(employee1.getName()); employee1=(Employees)session.get(Employees.class, 1); System.out.println(employee1.getName()); session.getTransaction().commit(); session.close(); //===================更新后二级缓存中相关数据失效 下次使用重新获取 Session session2=sessionFactory.openSession(); session2.beginTransaction(); Employees employee2=(Employees)session2.get(Employees.class, 1); System.out.println(employee2.getName()); session2.getTransaction().commit(); session2.close();
相关文章推荐
- 【Hibernate开发】对持久化对象和缓存机制的理解
- hibernate的缓存机制(转自javaEye)
- Hibernate 缓存机制
- 浅析Java的Hibernate框架中的缓存和延迟加载机制
- Hibernate的缓存机制
- Hibernate的缓存机制介绍
- Hibernate的缓存机制介绍
- Hibernate 所有缓存机制详解
- Hibernate——(5)持久化对象和一级缓存机制
- HIBERNATE的缓存机制
- Hibernate的缓存机制
- Hibernate 缓存机制浅析
- Hibernate 缓存机制
- Hibernate 缓存机制
- Hibernate的缓存机制
- 面试中问到HIBERNATE的缓存机制请问下该怎么回答
- Hibernate 缓存机制
- Hibernate——脏检查和缓存清理机制
- Hibernate学习笔记 -- day05 缓存、快照机制、对象状态
- 【hibernate框架】缓存机制之二级缓存