您的位置:首页 > 其它

Hibernate 缓存机制

2017-03-19 12:01 363 查看
Hibernate中缓存主要分为–一级缓存 和二级缓存。

一级缓存:又称为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();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: