Hibernate缓存以及哪些操作会向缓存中读取和存放数据
来源:互联网 发布:简谱变调软件下载 编辑:程序博客网 时间:2024/05/18 17:04
Hibernate缓存以及哪些操作会向缓存中读取和存放数据
Hibernate缓存
Hibernate有两级缓存,分别是一级缓存和二级缓存。一级缓存也叫Session级缓存,默认情况下就可以用,无需配置。一级缓存生命周期由Session对象决定,Session对象关闭,一级缓存也就消失。二级缓存也叫SessionFactory级缓存,需要配置后才能使用。二级缓存的生命周期比一级缓存的生命周期长,由SessionFactory对象决定,SessionFactory对象关闭,二级缓存也就消失。
哪些操作会向缓存中读取和存放数据?
测试之前先说一下Hibernate访问数据库,Hibernate对传统的JDBC进行了封装,一般我们访问数据库无非就是增、删、改、查这四个操作,而这四个操作均通过各自的SQL语句完成,所以Hibernate对数据库进行这四个操作时也离开不了SQL语句,如果我们配置Hibernate时配置了show_sql这个属性的话,一旦Hibernate对数据库进行了增、删、改、查操作的话,控制台就会将执行的SQL语句打印出来,这也就是下面我们为什么能将控制台有没有打印SQL语句作为Hibernate有没有访问数据库的原因。下面开始测试:
测试环境:
系统:Windows 10
JDK:1.8.102
Hibernate:5.2.10
软件:MyEclipse 2016
我们先看查询,查询我们常见的有get()、load()以及HQL中的Query对象的list()方法(后面为方便,我们称为query.list())和uniqueResult()方法(后面为方便,我们称为query.uniqueResult())这些方法。
先上结果:
get()、load()均会向缓存中存放以及读取数据,而query.list()和query.uniqueResult()会向缓存存放数据但不会从缓存中读取数据
get()方法:
测试之前先说一下get()方法是怎么查找数据的,它会先到一级缓存中去找,没有的话,它会到二级缓存中继续找,二级缓存中还没有的话,就会立马生成相应的查询SQL,并把这个SQL发送到数据库,到数据库中去找编号为7499的员工,如果数据库中也没找到的话,就会返回null。如果数据库中有的话就会返回查询结果,在它返回查询结果的同时,它还会把查到的结果放进缓存中(一二级缓存都会放)。
测试get()方法代码:
// get()会向缓存中存放和读取数据测试 public static void testGetCache(Session session){ try { Employee emp6=session.get(Employee.class, 7499); System.out.println(emp6); Employee emp7=session.get(Employee.class, 7499); System.out.println(emp7); } catch (Exception e) { e.printStackTrace(); }finally{ session.close(); } }
运行结果:
Hibernate: select employee0_.empno as empno1_0_0_, employee0_.ename as ename2_0_0_, employee0_.job as job3_0_0_, employee0_.sal as sal4_0_0_, employee0_.deptno as deptno5_0_0_, employee0_.hiredate as hiredate6_0_0_, employee0_.comm as comm7_0_0_, employee0_.mgr as mgr8_0_0_ from SCOTT.Emp employee0_ where employee0_.empno=?员工姓名:ALLEN 员工编号7499员工姓名:ALLEN 员工编号7499
代码中我们查询编号7499的员工查了2次,但运行结果中只打印了第一次查询的SQL语句,说明第一次是到数据库中查的,第二次没有去数据库中查,但第二次却依然查到了编号7499的员工,原因是因为Hibernate的缓存机制,第一次找到编号为7499的员工到后就会把7499的员工信息放进缓存中,当我们第二次再次查找的7499的员工信息时,由于在缓存中已经找到了,所以就直接返回结果,就不会到数据库中去查了,因此控制台并没有打印第二次的SQL语句。也就是说第二次查询是从缓存中查(读取)出来的。所以结果很明显:get()会向缓存中存放以及读取数据。
get()测试结果:get()会向缓存中存放以及读取数据
load()方法:
load()和get()查找数据的方式差不多,但又有点区别。load()也是先到一级缓存中去找,没找到的话继续到二级缓存中找,二级缓存中还没找到的话,它会返回一个查询结果的代理对象,当后面我们用到查询结果时,这个时候它才会生成相应的SQL语句,并把SQL发送到数据库,到数据库中去找,你后面如果没用到查询结果的话它不会生成查询的SQL,不会到数据库中去找。换句话说,就是你什么时候用到查询结果,他就什么时候去数据库中找,如果在数据库中没找到的话,就会报错,会报org.hibernate.ObjectNotFoundException的异常,导致程序中断。如果数据库中有的话就会返回查询结果,在它返回查询结果的同时,它还会把查到的结果放进缓存中(一二级缓存都会放)
测试load()方法代码:
// load()会向缓存中存放和读取数据测试 public static void testLoadCache(Session session){ try { Employee emp6=session.get(Employee.class, 7369); System.out.println(emp6); Employee emp7=session.get(Employee.class, 7369); System.out.println(emp7); } catch (Exception e) { e.printStackTrace(); }finally{ session.close(); } }
运行结果:
Hibernate: select employee0_.empno as empno1_0_0_, employee0_.ename as ename2_0_0_, employee0_.job as job3_0_0_, employee0_.sal as sal4_0_0_, employee0_.deptno as deptno5_0_0_, employee0_.hiredate as hiredate6_0_0_, employee0_.comm as comm7_0_0_, employee0_.mgr as mgr8_0_0_ from SCOTT.Emp employee0_ where employee0_.empno=?员工姓名:SMITH 员工编号7369员工姓名:SMITH 员工编号7369
代码中我们同样查询编号7369的员工查了2次,但运行结果中只打印了第一次查询的SQL语句,说明第一次是到数据库中查的,第二次没有去数据库中查,但第二次却依然查到了编号7369的员工,原因也是因为Hibernate的缓存机制,第一次找到编号为7369的员工后就会把7369的员工信息放进了缓存,第二次查找的7369的员工信息是从缓存中查(读取)出来的。所以load()也会向缓存中存放以及读取数据。
load()方法测试结果:load()会向缓存中存放以及读取数据
query.list()方法
测试query.list()方法代码:
// 测试query.list()会向缓存中存放数据但不会从缓存的读取数据 public static void testQueryListCache(Session session) { try { String hql="from Employee"; Query query=session.createQuery(hql); List<Employee> list=query.list(); for (int i=0;i<2;i++) { System.out.println("员工编号:"+list.get(i).getEmpNo()+" 员工姓名:"+list.get(i).getEmpName()); } System.out.println("------------------------------------------"); Employee emp=(Employee)session.get(Employee.class, 7654); System.out.println("员工编号:"+emp.getEmpNo()+" 员工姓名:"+emp.getEmpName()); System.out.println("------------------------------------------"); String hql2="from Employee"; Query query2=session.createQuery(hql2); List<Employee> list2=query2.list(); for (int i=0;i<2;i++) { System.out.println("员工编号:"+list2.get(i).getEmpNo()+" 员工姓名:"+list2.get(i).getEmpName()); } } catch (Exception e) { e.printStackTrace(); }finally{ session.close(); } }
运行结果:
Hibernate: select employee0_.empno as empno1_0_, employee0_.ename as ename2_0_, employee0_.job as job3_0_, employee0_.sal as sal4_0_, employee0_.deptno as deptno5_0_, employee0_.hiredate as hiredate6_0_, employee0_.comm as comm7_0_, employee0_.mgr as mgr8_0_ from SCOTT.Emp employee0_员工编号:20 员工姓名:empSu2员工编号:19 员工姓名:empSave2------------------------------------------员工编号:7654 员工姓名:MARTIN------------------------------------------Hibernate: select employee0_.empno as empno1_0_, employee0_.ename as ename2_0_, employee0_.job as job3_0_, employee0_.sal as sal4_0_, employee0_.deptno as deptno5_0_, employee0_.hiredate as hiredate6_0_, employee0_.comm as comm7_0_, employee0_.mgr as mgr8_0_ from SCOTT.Emp employee0_员工编号:20 员工姓名:empSu2员工编号:19 员工姓名:empSave2
测试代码中我们用query.list()方法去查询所有员工的编号和姓名查了两次(为了方便看结果,循环打印员工的编号和姓名时只循环了2次),分别在第一条虚线前和第二条虚线后。两条虚线之间我们用get()的方式查找了其中一名员工,看两条虚线间有没有打印get()查询员工的SQL语句来验证第一次query.list()查询后,有没有向缓存中存放数据。
运行结果可以看出,控制台将这两次query.list()查询所有员工的SQL语句都打印了出来,说明两次query.list()查询都是到数据库中查找的。两次query.list()查询之间我们用get()去查询了编号为7654的员工,运行结果显示我们查到了该员工的信息,但控制台却没有打印查询该员工信息的SQL语句,说明get()没有到数据库中去查,get()查到的编号为7654的员工信息不是从数据库中查到的,由于get()查找数据的顺序是先从缓存中找再到数据库中找,但我们用get()却查到了编号为7654的员工,说明get()查到的数据是从缓存中查到(读取到)的,观察整段测试代码,get()查询之前我们只进行了query.list()查询操作,所以很明显缓存中的信息是query.list()查到结果后放进去的,这就说明了query.list()会向缓存中存放数据,此时缓存中已经有了所有员工信息,但get()后面的query.list()查询操作在缓存中已经有要查找的信息时依旧是到数据库中查的,所以会发现query.list()并不会从缓存中查找(读取)数据。综上:测试query.list()会向缓存中存放数据但不会从缓存的读取数据
query.list()测试结果:query.list()会向缓存中存放数据但不会从缓存的读取数据
query.uniqueResult()方法:
测试query.uniqueResult()代码:
//测试query.uniqueResult()会向缓存中存放数据但不会从缓存的读取数据 public static void testQueryUniqueResultCache(Session session) { try { String hql="from Employee where empNo=7876"; Query query=session.createQuery(hql); Employee emp=(Employee)query.uniqueResult(); System.out.println("员工编号:"+emp.getEmpNo()+" 员工姓名:"+emp.getEmpName()); System.out.println("-------------------------------------------------"); //通过get()来测试query.list()有没有向缓存中存放数据 Employee emp3=(Employee)session.get(Employee.class, 7876); System.out.println("员工编号:"+emp3.getEmpNo()+" 员工姓名:"+emp3.getEmpName()); System.out.println("-------------------------------------------------"); String hql2="from Employee where empNo=7876"; Query query2=session.createQuery(hql2); Employee emp2=(Employee)query.uniqueResult(); System.out.println("员工编号:"+emp2.getEmpNo()+" 员工姓名:"+emp2.getEmpName()); } catch (Exception e) { e.printStackTrace(); }finally{ session.close(); } }
运行结果:
Hibernate: select employee0_.empno as empno1_0_, employee0_.ename as ename2_0_, employee0_.job as job3_0_, employee0_.sal as sal4_0_, employee0_.deptno as deptno5_0_, employee0_.hiredate as hiredate6_0_, employee0_.comm as comm7_0_, employee0_.mgr as mgr8_0_ from SCOTT.Emp employee0_ where employee0_.empno=7876员工编号:7876 员工姓名:ADAMS-------------------------------------------------员工编号:7876 员工姓名:ADAMS-------------------------------------------------Hibernate: select employee0_.empno as empno1_0_, employee0_.ename as ename2_0_, employee0_.job as job3_0_, employee0_.sal as sal4_0_, employee0_.deptno as deptno5_0_, employee0_.hiredate as hiredate6_0_, employee0_.comm as comm7_0_, employee0_.mgr as mgr8_0_ from SCOTT.Emp employee0_ where employee0_.empno=7876员工编号:7876 员工姓名:ADAMS
与上面的测试query.list()类似,我们用query.uniqueResult()查编号为7876的员工查了两次,分别是在第一条虚线前和 第二条虚线后。两条虚线中间我们用get()再次查找编号7876的员工,看两条虚线之间有没有打印get()查询的SQL语句来判断query.uniqueResult()有没有向缓存中放入数据。
结果显示两条虚线之外均有打印查询的SQL,说明两次query.uniqueResult()查询都是到数据库中去查的,从运行结果来看,两条虚线之间并没有打印SQL语句,说明我们用get()查找员工7876时并没有到数据库中去查,但是依然查到了员工信息,根据get()查找数据的顺序结合此时get()并没有到数据库中去查,可以知道,get()查到员工信息是从缓存中查(读取)到的,依旧是观察整段测试代码,get()查询员工前面除了query.uniqueResult()查询操作外并没有进行其它任何操作,所以,很显然,缓存中的员工信息是前面query.uniqueResult()查到结果后放进去的。到这就说明了query.uniqueResult()会向缓存中存放数据。
再来,结合get()后面的query.uniqueResult()查询操作,在缓存中已经有要查找的员工时,却还是到数据库中去查找。所以得出结论:query.uniqueResult()不会从缓存的读取数据。
综合就是:query.uniqueResult()会向缓存中存放数据但不会从缓存的读取数据
测试结果:query.uniqueResult()会向缓存中存放数据但不会从缓存的读取数据
说完了查询,我们说添加,添加我们常见的有save()和saveOrUpdate()
先上结果:
save()和saveOrUpdate()进行添加时,均会向缓存中存放数据。
save()方法:
测试save()方法代码
//测试save()会向缓存中存放数据 public static void testSaveCache(Session session) { try { Transaction tr=session.beginTransaction(); Employee emp1=new Employee(); emp1.setEmpName("empSave2"); session.save(emp1); System.out.println("添加的对象的主键为:"+emp1.getEmpNo()); Employee emp2=(Employee)session.get(Employee.class,emp1.getEmpNo()); System.out.println("员工姓名:"+emp2.getEmpName()); tr.commit();//只有当这句代码执行时,才会向数据库发送sql } catch (Exception e) { e.printStackTrace(); }finally{ session.close(); } }
运行结果:
Hibernate: select hibernate_sequence.nextval from dual添加的对象的主键为:19员工姓名:empSave2Hibernate: insert into SCOTT.Emp (ename, job, sal, deptno, hiredate, comm, mgr, empno) values (?, ?, ?, ?, ?, ?, ?, ?)
从代码可以看出,我们在tr.commit();这句代码之前我们又用get()查询了当前添加的对象,此时tr.commit();还没有执行,也就是事务还没提交,所以对象这个时候还没存进数据库,按理说我们应该查不到记录。
但从运行结果中可以看出,我们查到了数据,而且,控制台没有打印相关的查询SQL,说明我们用get()查找的员工信息不是从数据库中找的,结合get()查找数据是先从缓存再到数据库中找的顺序,所以我们能得出,查到的数据是从缓存中查到的,而在我们get()查询之前除了save()操作并没有其它操作,因此,缓存中的数据是save()放的,也就是说在我们调用save()添加时它会把添加的信息放进缓存里。
save()测试结果:save()会向缓存中存放数据
saveOrUpdate()方法:
测试saveOrUpdate()方法代码
//测试saveOrUpdate()进行添加时会向缓存中存放数据 public static void testSaveOrUpdateCache(Session session) { try { Transaction tx=session.beginTransaction(); Employee emp3=new Employee(); emp3.setEmpName("empSu2"); session.saveOrUpdate(emp3); System.out.println("添加的对象的主键为:"+emp3.getEmpNo()); Employee emp4=(Employee)session.get(Employee.class,emp3.getEmpNo()); System.out.println("员工姓名:"+emp4.getEmpName()); tx.commit();//只有当这句代码执行时,才会向数据库发送sql } catch (Exception e) { e.printStackTrace(); }finally{ session.close(); } }
运行结果:
Hibernate: select hibernate_sequence.nextval from dual添加的对象的主键为:20员工姓名:empSu2Hibernate: insert into SCOTT.Emp (ename, job, sal, deptno, hiredate, comm, mgr, empno) values (?, ?, ?, ?, ?, ?, ?, ?)
和测试save()一样,我们在tx.commit();这句代码之前我们又用get()查询了当前添加的对象,此时tr.commit();还没有执行,也就是事务还没提交,所以对象还没存进数据库,按理说我们应该查不到记录。
运行结果也和上面save()的一样,控制台并没有打印相关的查询SQL说明,说明我们用get()查找的员工信息不是从数据库中找的,结合get()查找数据是先从缓存再到数据库中找的顺序,所以我们能得出,查到的数据是从缓存中查到的,而在我们get()查询之前除了saveOrUpdate()操作并没有其它操作,因此,缓存中的信息是saveOrUpdate()操作放进去的,所以,saveOrUpdate()也会向缓存中存放数据。
saveOrUpdate()测试结果:saveOrUpdate()会向缓存中存放数据
以上均为个人理解,如有错误,欢迎指正
- Hibernate缓存以及哪些操作会向缓存中读取和存放数据
- 什么样的数据适合存放到第二级缓存中(并以Hibernate阐述缓存)
- Integer 生成对象时,介于-128~+127之间的数据会被存放到缓存中
- hibernate 支持哪些哪些缓存
- react中将数据存放在缓存中的方法和将数据从缓存中取出的方法
- hibernate一级缓存和二级缓存的区别与联系以及程序中缓存的分类
- Hibernate缓存机制以及一级缓存和二级缓存的作用
- Hibernate缓存机制以及一级缓存和二级缓存的作用
- Hibernate缓存机制以及一级缓存和二级缓存的作用
- Hibernate缓存机制以及一级缓存和二级缓存的作用
- Hibernate缓存机制以及一级缓存和二级缓存的作用
- hibernate中flush()、refresh()、clear()缓存操作
- Java实现向数据库中存放和读取图片
- Java实现向数据库中存放和读取图片
- Hibernate之数据缓存
- Hibernate数据缓存
- Hibernate 数据缓存
- hibernate 数据缓存
- CentOS7下安装apache-tomcat-9.0.0.M20.tar.gz
- linux安装make apache报错 Could not read symbols
- 反射(Reflection)基础总结
- MySQL观察
- C语言趣味程序(4)
- Hibernate缓存以及哪些操作会向缓存中读取和存放数据
- maven打包子项目war包项目时,不打包依赖项目jar包项目的原因,以及maven中不能单独打包子项目
- eclipse python numpy scipy
- js的相关题
- 牛顿法
- IDEA使用-1
- java操作hbase基础
- Markdown——编辑器语法——字体、字号与颜色
- Windows下tomcat正确安装使用方式