这篇博客主要记录SSH框架的相关面试知识点和题
1、Hibernate工作原理及为什么要用?
原理:
- 读取并解析配置文件
- 读取并解析映射信息,创建SessionFactory
- 打开Sesssion
- 创建事务Transation
- 持久化操作
- 提交事务
- 关闭Session
- 关闭SesstionFactory
为什么要用:
对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。
2. Hibernate是如何延迟加载?
1. Hibernate 延迟加载实现:a)实体对象 b)集合(Collection)
2. Hibernate 提供了属性的延迟加载功能
当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节省了服务器的内存开销,从而提高了服务器的性能。
3.Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系)
类与类之间的关系主要体现在表与表之间的关系进行操作,它们都是对对象进行操作;
我们程序中把所有的表与类都映射在一起,它们通过配置文件中的many-to-one、one-to-many、many-to-many、
4. 说下Hibernate的缓存机制
1. 内部缓存存在Hibernate中又叫一级缓存,属于应用事物级缓存
2. 二级缓存:
a) 应用及缓存
b) 分布式缓存
条件:数据不会被第三方修改、数据大小在可接受范围、数据更新频率低、同一数据被系统频繁使用、非 关键数据
c) 第三方缓存的实现
5. Hibernate的查询方式
hibernate的查询方式常见的主要分为三种: HQL, QBC(命名查询), 以及使用原生SQL查询(SqlQuery)
1、HQL查询
• HQL(Hibernate Query Language)提供了丰富灵活的查询方式,使用HQL进行查询也是Hibernate官方推荐使用的查询方式。
• HQL在语法结构上和SQL语句十分的相同,所以可以很快的上手进行使用。使用HQL需要用到Hibernate中的Query对象,该对象专门执行HQL方式的操作。
2、QBC(Query By Criteria)查询
• Criteria对象提供了一种面向对象的方式查询数据库。Criteria对象需要使用Session对象来获得。
• 一个Criteria对象表示对一个持久化类的查询。
3、原生SQL查询:
1 session.beginTransaction(); 2 String sql = "select id,username,userpwd from t_user"; 3 List list = session.createSQLQuery(sql).list(); 4 for(Object item : list){ 5 Object[] rows = (Object[]) item; 6 System.out.println("id:" + rows[0] + "username:" 7 + rows[1] + "userpwd:" + rows[2]); 8 } 9 session.getTransaction().commit();
6. 如何优化Hibernate?
hibernate是建立在JDBC基础上的框架,但他有很多JDBC所无法比拟的性能优化技术。下面介绍几种优化策略。
1.使用dynamic-insert与dynamic-update
在class标签中使用该属性,可以设置hibernate动态的生成SQL语句,而不是在hibernate启动时就生成预设的SQL语句。
当其设置为true时,hibernate会根据实际需求设置新增或更新的字段,而不是所有的字段。
<class name="com.hibernate.book" table="BOOK" dynamic-insert="true" dynamic-update="true">
2.延迟加载
为了避免在关联查询中带来无谓的开销而使用,即尽在需要读取数据库时才查询数据库。session的load()方法采用了,get()则没有。
(1)持久化对象的延迟加载
配置:
<class name="com.hibernate.Category" table="CATEGORY" lazy="true">
下述操作不会输出任何sql语句
Category category= (Category) session.load(Category.class, new Integer(1));
tx.commit();
注:
load()方法获取的不是真正的持久化对象,而是一个代理对象(包含目标对象的属性和方法)。
代理对象仅需要得到持久化类对象的引用,不需要获取所有属性值。
为顺利生成代理对象,hibernate的持久化类必须有公开的构造方法,不能声明为final。
(2)集合对象的延迟加载
地位:是延迟加载最重要的部分可以大幅度提高性能。
配置:
<class name="com.hibernate.Category" table="CATEGORY" lazy="true">
<set name="products" cascade="save-update" inverse="true" lazy="false">
</set>
</class>
下面操作不会查询product表的值:
Category category= (Category) session.load(Category.class, new Integer(1));
System.out.println(category.getName());
tx.commit();
注:product集合设置lazy='extra'后,调用product的size(), contains(), 和isEmpty()方法不会引发不必要的查询。
(3)属性的延迟加载
一些数据库表有大数据字段类型(blob,clob),但其使用麻烦,且大多数情况下对提高性能有限。
(4)延迟加载出现的违例问题
使用hibernate.initialize():在session关闭之前强制加载被关联的对象。
使用open session in view设计模式。
3. 集合对象的抓取策略
概念:指hibernate在读取关联对象时所采取的策略。
(1)查询抓取(select fetching):先通过一个sql语句查询持久化对象,再通过另一个查询语句查询关联的对象。设置该策略后仍可使用HQL或者Criteria对象重载抓取策略。
(2)子查询抓取(Subselect fetching):先通过一个sql语句查询持久化对象,再通过另一个子查询语句查询关联的对象。
(3)链接抓取(join fetching):使用外连接语句获取当前对象或者相关的对象。不会对使用HQL语句的查询生效,只对其他查询方式如:session.get(),criteria.list()有效。
(4)批量查询(Batch fetching):先通过查询获取一个主键或外键列表,再使用单条语句获取对象。hibernate在查询时会按照设置的数值分批查询数据。
4. hibernate的“1+N”问题
场景1:
Query对象的iterate()方法获取查询数据。当代码第一次使用iterate()方法时,hibernate会先获取id列表值,再通过N条语句获取数据并添加到缓存中。
若Query对象的iterate()方法总不能很好地命中缓存数据时,将大大影响其性能,此时可以采用list()方法;反之,若可以很好地命中缓存,则可很好地提高性能。
场景2:
一对多,在一方查找得到了n个对象, 那么又需要将n个对象关联的集合取出,于是本来的一条sql查询变成了n+1条 。
多对一,在多方查询得到了m个对象,那么也会将m个对象对应的1方的对象取出, 也变成了m+1。
解决:
(1)使用延迟加载,只有当需要关联对象(访问其属性,非id字段)时才会发生查询动作。
(2)采用二级缓存, 即使第一次查询很慢,之后命中缓存也是很快的。
7、hibernate的核心类是什么,它们的相互关系是什么?重要的方法是什么?
Configuration 接口:配置Hibernate,根据其启动hibernate,创建SessionFactory 对象;
SessionFactory 接口:初始化Hibernate,充当数据存储源的代理,创建session 对象,sessionFactory 是线程安全的,意味着它的同一个实例可以被应用的多个线程共享,是重量级、二级缓存;Session 接口:负责保存、更新、删除、加载和查询对象,是线程不安全的,避免多个线程共享同一个session,是轻量级、一级缓存;
Session如下方法: save,load,update,delete,
Query q=CreateQuery(“from Customer where customerName=:customerName”)
beginTransaction, close, transaction, commit
Transaction 接口:管理事务;
Query 和Criteria 接口:执行数据库的查询。
Struts类型面试题
1、 说说struts框架的方法的工作原理或流程
struts是采用Java Servlet/JavaServer Pages技术,开发Web应用程序的开放源码的framework。
采用Struts能开发出基于MVC(Model-View-Controller)设计模式的应用构架。 Struts有如下的主要功能:
一.包含一个controller servlet,能将用户的请求发送到相应的Action对象。
二.JSP自由tag库,并且在controller servlet中提供关联支持,帮助开发员创建交互式表单应用。
三.提供了一系列实用对象:XML处理、通过Java reflection APIs自动处理JavaBeans属性、国际化的提示和消息。
对于采用Struts框架的web应用, 在web应用启动时会加载并初始化ActionServlet,ActionServlet从struts-config.xml中读取配置信息,
把它们存放到各种配置对象中,例如把Action的映射信息存放在ActionMapping对象中。
当ActionServlet接收到客户请求时,执行以下流程:
1.检索和用户请求匹配的ActionMapping实例,如果不存在,就返回用户请求路径无效信息;
2.如果ActionForm实例不存在,就创建一个ActionForm对象并在其中保存客户提交的表单内容;
3.根据配置信息决定是否调用ActionForm的validate()方法;
4.如果ActionForm的validate()方法返回null或返回一个不包含ActionMessage的ActionErrors对象,就表示表单验证成功;
5.ActionServlet根据ActionMapping实例包含的映射信息将请求转发给Action(如果Action实例不存在,就先创建Action实例),然后调用Action的excute()方法;
6.Action的excute()方法返回一个ActionForward对象,ActionServlet再把客户请求转发给ActionForward对象指向的JSP组件;
7.ActionForward对象指向的JSP组件生成动态网页,返回给客户。
2、Struts对MVC的体现
M: 在Struts中,模型由JavaBean和EJB组件组成,用来实现程序的业务逻辑部分.
C: ActionServlet,RequestProcessor和Struts辅助类来实现控制器。ActionServlet是Struts中的核心控制器ActionServlet会根据在Struts配置文件中的配置将控制权转交给相应的Action 类。
Action 类是业务的代理,在Action类中可以调用模型组件或者编写其他业务逻辑代码来完成一项具体的业务。
V: Struts框架中的视图主要由JSP文件构成,在JSP文件中可应用Struts标签和自定义标签来表现模型组件中的数据进行简单的处理。
ActionForm Bean实际上是一个遵循了特殊约定的JavaBean,在Struts中ActionForm Bean可看作为一个中间存储器在视图与控制器之间进行数据传递。
3、struts1.2和struts2.0的区别?
a、Action类:
struts1.2要求Action类继承一个基类。struts2.0 Action可以是简单的JOPO对象或者(都会)继承ActionSupport基类
b、线程模式
struts1.2 Action是单例模式的并且必须是线程安全的,因为仅有一个Action的实例来处理所有的请求。
单例策略限制了Struts1.2 Action能做的事情,并且开发时特别小心。Action资源必须是线程安全的或同步的。
struts2.0 Action为每一个请求产生一个实例,因此没有线程安全问题。
c、Servlet依赖
struts1.2 Action依赖于Servlet API,因为当一个Action被调用时HttpServletRequest和HttpServletResponse被传递给execut方法。
struts2.0 Action不依赖于容器,允许Action脱离容器单独测试。如果需要,Struts2 Action仍然可以访问初始的Request和Response。
但是,其他的元素减少或者消除了直接访问HttpServletRequest和HttpServletResponse的必要性。
d、可测性
测试struts1.2 Action的一个主要问题是execute方法暴露了Servlet API(这使得测试要依赖于容器)。一个第三方扩展:struts TestCase
提供了一套struts1.2的模拟对象来进行测试。
Struts2.0 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”也使得测试更容易。
4、struts如何实现国际化
以下以两国语言(中文,英文)为例:
1. 在工程中加入Struts支持
2. 编辑ApplicationResource.properties文件,在其中加入要使用国际化的信息, 例如: lable.welcome.china=Welcome!!!
3. 创建英文资源文件ApplicationResource_en.properites
4. 创建临时中文资源文件ApplicationResource_temp.properites 例如:lable.welcom.china=中国欢迎您!
5. 对临时中文资源文件进行编码转换。可以使用myeclipse的插件,也可以在dos下执行:
native2ascii -encoding gb2312 ApplicationResource_temp.properties ApplicationResource_zh_CN.properties
6. 在jsp中加入struts的bean标记库
5、 Struts框架的数据验证可分为几种类型?
表单验证(由ActionForm Bean处理):如果用户没有在表单中输入姓名,就提交表单,将生成表单验证错误
业务逻辑验证(由Action处理):如果用户在表单中输入的姓名为“Monster”,按照本应用的业务规则,不允许向“Monster”打招呼,因此将生成业务逻辑错误。
6、简述Form Bean的表单验证流程
1、当用户提交了HTML表单,Struts框架自动把表单数据组装到ActionForm Bean中。
2、接下来Struts框架会调用ActionForm Bean的validate()方法进行表单验证。
3、如果validate()方法返回的ActionErrors 对象为null,或者不包含任何ActionMessage对象,就表示没有错误,数据验证通过。
4、如果ActionErrors中包含ActionMessage对象,就表示发生了验证错误,Struts框架会把ActionErrors对象保存到request范围内,然后把请求转发到恰当的视图组件,视图组件通过标签把request范围内的ActionErrors对象中包含的错误消息显示出来,提示用户修改错误。
7、简单叙述ActionForm Bean的作用
1、ActionForm Bean也是一种JavaBean,除了具有一些JavaBean的常规方法,还包含一些特殊的方法,用于验证HTML表单数据以及将其属性重新设置为默认值。
2、Struts框架利用ActionForm Bean来进行View组件和Controller组件之间表单数据的传递。
3、Struts框架把View组件接受到的用户输入的表单数据保存在ActionForm Bean中,把它传递给Controller组件,Controller组件可以对ActionForm Bean中的数据进行修改JSP文件使用Struts标签读取修改后的ActionForm Bean的信息,重新设置HTML表单。
8、在struts配置文件中action元素包含哪些属性和子元素?
path属性:指定请求访问Action的路径
type属性:指定Action的完整类名
name属性:指定需要传递给Action的ActionForm Bean
scope属性:指定ActionForm Bean的存放范围
validate属性:指定是否执行表单验证
input属性:指定当表单验证失败时的转发路径。
元素还包含一个子元素,它定义了一个请求转发路径。
9、Struts优缺点
优点:
1. 实现MVC模式,结构清晰,使开发者只关注业务逻辑的实现.
2.有丰富的tag可以用 ,Struts的标记库(Taglib),如能灵活动用,则能大大提高开发效率
3. 页面导航
使系统的脉络更加清晰。通过一个配置文件,即可把握整个系统各部分之间的联系,这对于后期的维护有着莫大的好处。尤其是当另一批开发者接手这个项目时,这种优势体现得更加明显。
4. 提供Exception处理机制 .
5. 数据库链接池管理
6. 支持I18N
缺点:
一、 转到展示层时,需要配置forward,如果有十个展示层的jsp,需要配置十次struts,而且还不包括有时候目录、文件变更,需要重新修改forward,
注意,每次修改配置之后,要求重新部署整个项目, 而tomcate这样的服务器,还必须重新启动服务器
二、 Struts 的Action必需是thread-safe方式,它仅仅允许一个实例去处理所有的请求。
所以action用到的所有的资源都必需统一同步,这个就引起了线程安全的问题。
三、 测试不方便. Struts的每个Action都同Web层耦合在一起,这样它的测试依赖于Web容器,单元测试也很难实现。不过有一个Junit的扩展工具Struts TestCase可以实现它的单元测试。
四、 类型的转换. Struts的FormBean把所有的数据都作为String类型,它可以使用工具Commons-Beanutils进行类型转化。但它的转化都是在Class级别,而且转化的类型是不可配置的。
类型转化时的错误信息返回给用户也是非常困难的。
五、 对Servlet的依赖性过强. Struts处理Action时必需要依赖ServletRequest 和ServletResponse,所有它摆脱不了Servlet容器。
六、 前端表达式语言方面.Struts集成了JSTL,所以它主要使用JSTL的表达式语言来获取数据。可是JSTL的表达式语言在Collection和索引属性方面处理显得很弱。
七、 对Action执行的控制困难. Struts创建一个Action,如果想控制它的执行顺序将会非常困难。甚至你要重新去写Servlet来实现你的这个功能需求。
八、 对Action 执行前和后的处理. Struts处理Action的时候是基于class的hierarchies,很难在action处理前和后进行操作。
九、 对事件支持不够. 在struts中,实际是一个表单Form对应一个Action类(或DispatchAction),换一句话说:在Struts中实际是一个表单只能 对应一个事件,
struts这种事件方式称为application event,application event和component event相比是一种粗粒度的事件