hibernate缓存机制详细分析
- 格式:doc
- 大小:182.50 KB
- 文档页数:18
3.1、缓存策略3.1.1、一级缓存之前每一个数据库操作都是一个Session,那么对于Session来说本身是存在着缓存,可以保留之前的查询结果。
但是对于Session的缓存只针对于一个Session有效,那么如果现在想针对于多个Session 有作用,则必须在SessionFactory上配置缓存,那么这样的缓存称为二级缓存。
在Hiernate按ID查询有两个方法:load、get那么下面使用以上的查询方法,查询两次程序虽然调用了两次load方法,但是只发出了一条的查询命令,证明,第一次的查询结果被保存下来了,那么这就是一级缓存。
与之前的相比,查询了两次操作,所以此时,证明一级缓存只是针对于一个Session起作用的。
但是一级缓存是无法关闭的,始终会存在。
从运行结果可以发现,如果之前先进行了保存操作,那么之后再查询的话也不会重新发出查询语句。
证明实体被缓存下来。
问题:如果现在要求使用程序插入100000万条记录?该怎么办?如果使用Hibernate处理的话,则可能会出现内存的溢出,所以在这种情况下首先是绝对不建议使用Hibernate完成的,就使用最基本的JDBC操作完成即可。
如果非要使用Hibernate做,则必须使用到Session中关于缓存的一些操作方法:·清空Session中的所有缓存:clear()·清空Session中一个指定的实体:evict(Object obj)例如:下面验证clear()方法因为程序中,将所有的缓存清空了,所以之后再查询相同实体的时候,在Session中已以上因为只清空了一个实体,所以只发出了三个查询语句。
那么就可以通过以上的方式完成100W条记录的插入思路:按照每十条清空缓存的操作,并将缓存中的内容强制性的写到数据库之中3.1.2、二级缓存(重点)在Hibernate本身中支持了多种的二级缓存组件。
本次使用EHcache。
如果要想使用ehcache话,则首先必须进行配置,配置ehcache的缓存文件。
1、jsp和servlet的区别、共同点、各自应用的范围??JSP是Servlet技术的扩展,本质上就是Servlet的简易方式。
JSP编译后是“类servlet”。
Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。
而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。
JSP侧重于视图,Servlet主要用于控制逻辑。
在struts框架中,JSP位于MVC设计模式的视图层,而Servlet位于控制层.2、cookie和session的作用、区别、应用范围,session的工作原理Cookie:主要用在保存客户端,其值在客户端与服务端之间传送,不安全,存储的数据量有限。
Session:保存在服务端,每一个session在服务端有一个sessionID作一个标识。
存储的数据量大,安全性高。
占用服务端的内存资源。
3、jstl是什么?优点有哪些??JSTL(JSP Standard Tag Library,JSP标准标签库)是一个不断完善的开放源代码的JSP标签库,由四个定制标记库(core、format、xml和sql)和一对通用标记库验证器(ScriptFreeTLV和PermittedTaglibsTLV)组成。
优点有:最大程序地提高了WEB应用在各应用服务器在应用程序服务器之间提供了一致的接口,最大程序地提高了1、在应用程序服务器之间提供了一致的接口,之间的移植。
2、简化了JSP和WEB应用程序的开发。
3、以一种统一的方式减少了JSP中的scriptlet代码数量,可以达到没有任何scriptlet 代码的程序。
在我们公司的项目中是不允许有任何的scriptlet代码出现在JSP中。
4、允许JSP设计工具与WEB应用程序开发的进一步集成。
相信不久就会有支持JSTL的IDE 开发工具出现。
4、j2ee的优越性主要表现在哪些方面?MVC模式a、J2EE基于JAVA技术,与平台无关b、J2EE拥有开放标准,许多大型公司实现了对该规范支持的应用服务器。
第一:数据库连接不需要我们自己来管理,如打开和关闭(优点吧)第二:Hibernate对原来的SQL语句进行了封装,以前写很多SQL语句,现在你在保存的时候直接可以用SA VE(对象)来实现了。
(节省代码吧)第三:原来是对表操作,现在是对对象操作,想法上是不是更好呢?都是对象。
Hibernate优点(1) 对象/关系数据库映射(ORM)它使用时只需要操纵对象,使开发更对象化,抛弃了数据库中心的思想,完全的面向对象思想(2) 透明持久化(persistent)带有持久化状态的、具有业务功能的单线程对象,此对象生存期很短。
这些对象可能是普通的JavaBeans/POJO,这个对象没有实现第三方框架或者接口,唯一特殊的是他们正与(仅仅一个)Session相关联。
一旦这个Session被关闭,这些对象就会脱离持久化状态,这样就可被应用程序的任何层自由使用。
(例如,用作跟表示层打交道的数据传输对象。
)(3) 事务Transaction(org.hibernate.Transaction)应用程序用来指定原子操作单元范围的对象,它是单线程的,生命周期很短。
它通过抽象将应用从底层具体的JDBC、JTA以及CORBA事务隔离开。
某些情况下,一个Session之内可能包含多个Transaction对象。
尽管是否使用该对象是可选的,但无论是使用底层的API 还是使用Transaction对象,事务边界的开启与关闭是必不可少的。
(4) 它没有侵入性,即所谓的轻量级框架(5) 移植性会很好(6) 缓存机制,提供一级缓存和二级缓存(7) 简洁的HQL编程2. Hibernate缺点(1) Hibernate在批量数据处理时有弱势(2) 针对单一对象简单的增删查改,适合于Hibernate,而对于批量的修改,删除,不适合用Hibernate,这也是OR框架的弱点;要使用数据库的特定优化机制的时候,不适合用Hibernate1.strutsstruts框架具有组件的模块化,灵活性和重用性的优点,同时简化了基于MVC的web应用程序的开发。
java三大框架是什么Java三大框架是什么一、介绍Java是一种广泛使用的编程语言,由于其跨平台性和丰富的类库支持,成为了企业级应用开发的首选语言。
在Java开发中,框架是非常重要的组成部分,它们提供了一套结构化的工具和方法来简化开发流程并提高代码的重用性和可维护性。
在众多Java框架中,有三个最重要、最流行且被广泛使用的框架,它们分别是Spring框架、Hibernate框架和Struts框架。
二、Spring框架1. 简介Spring框架是一个轻量级的Java开发框架,最初用于解决企业级应用开发中的复杂性和耦合性问题。
Spring提供了一系列的模块和组件,为开发者提供了全面的解决方案,例如依赖注入、AOP(面向切面编程)、IoC(控制反转)等。
Spring框架的核心是IoC容器,它通过管理对象的生命周期和控制对象之间的依赖关系,简化了开发流程。
2. 主要特点和优势(1)松耦合:Spring框架通过IoC容器管理对象之间的依赖关系,使得应用程序的各个组件之间变得松散耦合,便于维护和升级。
(2)面向切面编程:Spring框架支持AspectJ规范,可以通过AOP实现横切关注点的模块化,并将其与业务逻辑分离,提高了代码的可维护性和重用性。
(3)可扩展性:Spring框架采用模块化的设计,开发者可以根据需要选择性地使用各个模块,使得框架具有很高的可扩展性和灵活性。
(4)测试支持:Spring框架提供了对单元测试的支持,可以方便地对代码进行单元测试和集成测试。
3. 使用场景Spring框架广泛应用于企业级应用开发,特别是在大规模和复杂度高的项目中表现出色。
由于其完善的设计和优秀的生态系统,Spring框架不仅可以用于开发Web应用程序,还可以用于开发移动应用、分布式系统、大数据系统等各种类型的应用。
三、Hibernate框架1. 简介Hibernate框架是一个优秀的Java持久化框架,它简化了对象与数据库之间的映射和操作,提高了开发效率和代码的可维护性。
Hibernate1.Hibernate 的初始化.读取Hibernate 的配置信息-〉创建Session Factory1)创建Configeration类的实例。
它的构造方法:将配置信息(Hibernate config.xml)读入到内存。
一个Configeration 实例代表Hibernate 所有Java类到Sql数据库映射的集合。
2)创建SessionFactory实例把Configeration 对象中的所有配置信息拷贝到SessionFactory的缓存中。
SessionFactory的实例代表一个数据库存储员源,创建后不再与Configeration 对象关联。
缓存(cache):指Java对象的属性(通常是一些集合类型的属性--占用内存空间。
SessionFactory的缓存中:Hibernate 配置信息。
OR映射元数据。
缓存-大:重量级对象小:轻量级对象3)调用SessionFactory创建Session的方法1】用户自行提供JDBC连接。
Connection con=dataSource.getConnection(); Session s=sessionFactory.openSession(con);2】让SessionFactory提供连接Session s=sessionFactory.openSession();4)通过Session 接口提供的各种方法来操纵数据库访问。
Hibernate 的缓存体系一级缓存:Session 有一个内置的缓存,其中存放了被当前工作单元加载的对象。
每个Session 都有自己独立的缓存,且只能被当前工作单元访问。
二级缓存:SessionFactory的外置的可插拔的缓存插件。
其中的数据可被多个Session共享访问。
SessionFactory的内置缓存:存放了映射元数据,预定义的Sql语句。
Hibernate 中Java对象的状态1.临时状态(transient)特征:1】不处于Session 缓存中2】数据库中没有对象记录Java如何进入临时状态1】通过new语句刚创建一个对象时2】当调用Session 的delete()方法,从Session 缓存中删除一个对象时。
(问答题+选择题(在55页))Java工程师(程序员)面题Struts,Spring,Hibernate三大框架1.Hibernate工作原理及为什么要用?原理:1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3.打开Session 4.创建事务Transation 5.持久化操作6.提交事务7.关闭Session 8.关闭SesstionFactory为什么要用:1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。
他很大程度的简化DAO层的编码工作3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
4. hibernate的性能非常好,因为它是个轻量级框架。
映射的灵活性很出色。
它支持各种关系数据库,从一对一到多对多的各种复杂关系。
2.Hibernate是如何延迟加载?1. Hibernate2延迟加载实现:a)实体对象b)集合(Collection)2. Hibernate3 提供了属性的延迟加载功能当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节省了服务器的内存开销,从而提高了服务器的性能。
3.Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系)类与类之间的关系主要体现在表与表之间的关系进行操作,它们都是对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配置文件中的many-to-one、one-to-many、many-to-many4.Struts1流程:1、客户端浏览器发出HTTP请求。
2、根据web.xml配置,该请求被ActionServlet接收。
3、根据struts-config.xml配置,ActionServlet先将请求中的参数填充到ActionForm中,然后ActionServlet再将请求发送到Action 进行处理。
在本篇随笔里将会分析一下hibernate的缓存机制,包括一级缓存(session级别)、二级缓存(sessionFactory级别)以及查询缓存,当然还要讨论下我们的N+1的问题。
随笔虽长,但我相信看完的朋友绝对能对hibernate的N+1问题以及缓存有更深的了解。
一、N+1问题首先我们来探讨一下N+1的问题,我们先通过一个例子来看一下,什么是N+1问题:list()获得对象:/*** 此时会发出一条sql,将30个学生全部查询出来*/List<Student> ls = (List<Student>)session.createQuery("from Stude nt").setFirstResult(0).setMaxResults(30).list();Iterator<Student> stus =ls.iterator();for(;stus.hasNext();){Student stu =(Student)stus.next();System.out.println(stu.getName());}如果通过list()方法来获得对象,毫无疑问,hibernate会发出一条sql语句,将所有的对象查询出来,这点相信大家都能理解Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.rid as rid2_, student0_.sex as sex2_ from t_student student0_ limit ?那么,我们再来看看iterator()这种情况iterator()获得对象/*** 如果使用iterator方法返回列表,对于hibernate而言,它仅仅只是发出取id列表的sql* 在查询相应的具体的某个学生信息时,会发出相应的SQL去取学生信息* 这就是典型的N+1问题* 存在iterator的原因是,有可能会在一个session中查询两次数据,如果使用list每一次都会把所有的对象查询上来* 而是要iterator仅仅只会查询id,此时所有的对象已经存储在一级缓存(session的缓存)中,可以直接获取*/Iterator<Student> stus = (Iterator<Student>)session.createQuery("fro m Student").setFirstResult(0).setMaxResults(30).iterate();for(;stus.hasNext();){Student stu =(Student)stus.next();System.out.println(stu.getName());}在执行完上述的测试用例后,我们来看看控制台的输出,看会发出多少条sql 语句:Hibernate: select student0_.id as col_0_0_ from t_student student0_ limit ? Hibernate: select student0_.id as id2_0_, student0_.name as name2_0_, student0 _.rid as rid2_0_, student0_.sex as sex2_0_ from t_student student0_ where stud ent0_.id=?沈凡Hibernate: select student0_.id as id2_0_, student0_.name as name2_0_, student0 _.rid as rid2_0_, student0_.sex as sex2_0_ from t_student student0_ where stud ent0_.id=?王志名Hibernate: select student0_.id as id2_0_, student0_.name as name2_0_, student0 _.rid as rid2_0_, student0_.sex as sex2_0_ from t_student student0_ where stud ent0_.id=?叶敦.........我们看到,当如果通过iterator()方法来获得我们对象的时候,hibernate首先会发出1条sql去查询出所有对象的id 值,,当我们如果需要查询到某个对象的具体信息的时候,hibernate此时会根据查询出来的id 值再发sql语句去从数据库中查询对象的信息,这就是典型的N+1的问题。
那么这种N+1 问题我们如何解决呢,其实我们只需要使用list() 方法来获得对象即可。
但是既然可以通过list() 我们就不会出现N+1的问题,那么我们为什么还要保留iterat or()这种形式呢?我们考虑这样一种情况,如果我们需要在一个session当中要两次查询出很多对象,此时我们如果写两条list()时,hibernate此时会发出两条sql 语句,而且这两条语句是一样的,但是我们如果第一条语句使用list(),而第二条语句使用iterator()的话,此时我们也会发两条sql语句,但是第二条语句只会将查询出对象的id,所以相对应取出所有的对象而已,显然这样可以节省内存,而如果再要获取对象的时候,因为第一条语句已经将对象都查询出来了,此时会将对象保存到session的一级缓存中去,所以再次查询时,就会首先去缓存中查找,如果找到,则不发sql语句了。
这里就牵涉到了接下来这个概念:hibernate的一级缓存。
二、一级缓存(session级别)我们来看看hibernate提供的一级缓存:/*** 此时会发出一条sql,将所有学生全部查询出来,并放到sessio n的一级缓存当中* 当再次查询学生信息时,会首先去缓存中看是否存在,如果不存在,再去数据库中查询* 这就是hibernate的一级缓存(session缓存)*/List<Student> stus = (List<Student>)session.createQuery("from Stu dent").setFirstResult(0).setMaxResults(30).list ();Student stu = (Student)session.load(Student.class, 1);我们来看看控制台输出:Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.rid as rid2_, student0_.sex as sex2_ from t_student student0_ limit ?我们看到此时hibernate仅仅只会发出一条sql 语句,因为第一行代码就会将整个的对象查询出来,放到session的一级缓存中去,当我如果需要再次查询学生对象时,此时首先会去缓存中看是否存在该对象,如果存在,则直接从缓存中取出,就不会再发sql了,但是要注意一点:hibernate的一级缓存是session级别的,所以如果session关闭后,缓存就没了,此时就会再次发sql去查数据库。
try{session =HibernateUtil.openSession();/*** 此时会发出一条sql,将所有学生全部查询出来,并放到sessio n的一级缓存当中* 当再次查询学生信息时,会首先去缓存中看是否存在,如果不存在,再去数据库中查询* 这就是hibernate的一级缓存(session缓存)*/List<Student> stus = (List<Student>)session.createQuery("from Stu dent").setFirstResult(0).setMaxResults(30).list ();Student stu = (Student)session.load(Student.class, 1);System.out.println(stu.getName() + "-----------");}catch(Exception e){e.printStackTrace();}finally{HibernateUtil.close(session);}/*** 当session关闭以后,session的一级缓存也就没有了,这时就又会去数据库中查询*/session =HibernateUtil.openSession();Student stu = (Student)session.load(Student.class, 1);System.out.println(stu.getName() + "-----------");Hibernate: select student0_.id as id2_, student0_.name as name2_, student0_.sex as sex2_, student0_.rid as rid2_ from t_student student0_ limit ? Hibernate: select student0_.id as id2_2_, student0_.name as name2_2_, student0 _.sex as sex2_2_, student0_.rid as rid2_2_, classroom1_.id as id1_0_, classroom 1_.name as name1_0_, classroom1_.sid as sid1_0_, special2_.id as id0_1_, speci al2_.name as name0_1_, special2_.type as type0_1_ from t_student student0_ le ft outer join t_classroom classroom1_ on student0_.rid=classroom1_.id left outer join t_special special2_ on classroom1_.sid=special2_.id where student0_.id=?我们看到此时会发出两条sql语句,因为session关闭以后,一级缓存就不存在了,所以如果再查询的时候,就会再发sql。