Hibernate面试

1.Hibernate session接口的get和load方法有何异同? 
答: 其实它们也没有什么不同的, 作用其实都是一样的,但是有一定的区别,get是每次都会从数据库取数据以保证数据的可靠性,而load会返回proxy,相当于是一个存根,它的值会去hibernate中的session的二级缓存里去找,如果找不到目则会laxy load一下,简单来说,用get的时候,当为空的时候不会抛出异常,反之load会抛. 

2.在持久化层,对象分为哪些状态?分别列出来. 
答:瞬时态(Transient)、持久态(Persistent)、脱管态(Detached)。 
瞬时态(Transient) 
是对象是创建时,瞬时对象在内存孤立存在,它是携带信息的载体,不和数据库的数据有任何关联关系,在Hibernate中,可通过session的save()或 saveOrUpdate()方法将瞬时对象与数据库相关联,并将数据对应的插入数据库中,此时该瞬时对象转变成持久化对象。 

持久态(Persistent) 
是该对象在数据库中已有对应的记录,并拥有一个持久化标识,如果是用hibernate的delete()方法,对应的持久对象就变成瞬时对象,因数据库中的对应数据已被删除,该对象不再与数据库的记录关联。 
    当一个session执行close()或clear()、evict()之后,持久对象变成脱管对象,此时持久对象会变成脱管对象,此时该对象虽然具有数据库识别值,但它已不在hibernate持久层的管理之下。 
  持久对象具有如下特点: 
     1. 和session实例关联; 
     2. 在数据库中有与之关联的记录。

 
脱管态(Detached) 
当与某持久对象关联的session被关闭后,该持久对象转变为脱管对象。当脱管对象被重新关联到session上时,并再次转变成持久对象。 
       脱管对象拥有数据库的识别值,可通过update()、saveOrUpdate()等方法,转变成持久对象。 
       脱管对象具有如下特点: 
    1.本质上与瞬时对象相同,在没有任何变量引用它时,JVM会在适当的时候将它回收; 
   2. 比瞬时对象多了一个数据库记录标识值。 


3.lock和update区别 
答: update是把一个已经更改过的脱管状态的对象变成持久状态 
lock是把一个没有更改过的脱管状态的对象变成持久状态(针对的是因Session的关闭 而处于脱管状态的po对象(2),不能针对因delete而处于脱管状态的po对象) 
对应更改一个记录的内容,两个的操作不同: 
update的操作步骤是: 
(1)属性改动后的脱管的对象的修改->调用update 
lock的操作步骤是: 
(2)调用lock把未修改的对象从脱管状态变成持久状态-->更改持久状态的对象的内容-->等待flush或者手动flush 


4.save 和update区别 
答: save是把一个对象做为一个新的数据保存, update则是把一个脱管状态的对象或自由态对象(一定要和一个记录对应)更新到数据库,其实一个是保存一个是更新,一看都知道是有什么区别了。 


5.update 和saveOrUpdate区别 
答:这个是比较好理解的,顾名思义,saveOrUpdate基本上就是合成了save和update,而update只是update;引用hibernate reference中的一段话来解释他们的使用场合和区别 
通常下面的场景会使用update()或saveOrUpdate(): 
程序在第一个session中加载对象,接着把session关闭 
该对象被传递到表现层 
对象发生了一些改动 
该对象被返回到业务逻辑层最终到持久层 
程序创建第二session调用第二个session的update()方法持久这些改动 
saveOrUpdate(po)做下面的事: 
如果该po对象已经在本session中持久化了,在本session中执行saveOrUpdate不做任何事 
如果savaOrUpdate(新po)与另一个与本session关联的po对象拥有相同的持久化标识(identifier),抛出一个异常 
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [org.itfuture.www.po.Xtyhb#5] 
saveOrUpdate如果对象没有持久化标识(identifier)属性,对其调用save() ,否则update() 这个对象      


6.flush和update区别 
答:这两个的区别好理解update操作的是在自由态或脱管状态(因session的关闭而处于脱管状态)的对象//updateSQL 
而flush是操作的在持久状态的对象。 
默认情况下,一个持久状态的对象的改动(包含set容器)是不需要update的,只要你更改了对象的值,等待hibernate flush就自动更新或保存到数据库了。hibernate flush发生在以下几种情况中: 
1, 调用某些查询的和手动flush(),session的关闭、SessionFactory关闭结合 
get()一个对象,把对象的属性进行改变,把资源关闭。 

2,transaction commit的时候(包含了flush) 


Hibernate工作原理及为什么要用:

原理:

hibernate,通过对jdbc进行封装,对 java类和 关系数据库进行mapping,实现了对关系数据库的面向对象方式的操作,改变了传统的jdbc + sql操作数据的方式,从而使开发人员可以用更多精力进行对象方面的开发

1.读取并解析配置文件

2.读取并解析映射信息,创建SessionFactory

3.打开Sesssion

4.创建事务Transation

5.持久化操作

6.提交事务

7.关闭Session

8.关闭SesstionFactory

为什么要用:

1.    对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。

2.    Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作

3.    hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。

什么是Hibernate延迟加载

延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。在Hibernate中提供了对实体对象的延迟加载以及对集合的延迟加载,另外在Hibernate3中还提供了对属性的延迟加载。

 

Hibernate中类之间的关联关系有几种(如:一对多、多对多的关系)

  many-to-one、one-to-many、many-to-many、 one-to-one

 

Hibernate的缓存机制

一、hibernate一级缓存

(1)hibernate支持两个级别的缓存,默认只支持一级缓存;

(2)每个Session内部自带一个一级缓存;

(3)某个Session被关闭时,其对应的一级缓存自动清除;

二、hibernate二级缓存

(1) 二级缓存独立于session,默认不开启;

题目5: Hibernate的查询方式

本地SQL查询、Criteria、Hql

 

优化Hibernate

1.使用双向一对多关联,不使用单向一对多

2.不用一对一,用多对一取代

3.配置对象缓存,不使用集合缓存

 

Struts工作机制?为什么要使用Struts?

工作机制:

Struts的工作流程:

在web应用启动时就会加载初始化ActionServlet,ActionServlet从

struts-config.xml文件中读取配置信息,把它们存放到各种配置对象

当ActionServlet接收到一个客户请求时,将执行如下流程.

 -(1)检索和用户请求匹配的ActionMapping实例,如果不存在就返回请求路径无效信息;

 -(2)如果ActionForm实例不存在,就创建一个ActionForm对象,把客户提交的表单数据保存到ActionForm对象中;

 -(3)根据配置信息决定是否需要表单验证.如果需要验证,就调用ActionForm的validate()方法;

 -(4)如果ActionForm的validate()方法返回null或返回一个不包含ActionMessage的ActuibErrors对象, 就表示表单验证成功;

 -(5)ActionServlet根据ActionMapping所包含的映射信息决定将请求转发给哪个Action,如果相应的 Action实例不存在,就先创建这个实例,然后调用Action的execute()方法;

 -(6)Action的execute()方法返回一个ActionForward对象,ActionServlet在把客户请求转发给 ActionForward对象指向的JSP组件;

 -(7)ActionForward对象指向JSP组件生成动态网页,返回给客户;

 

为什么要用:

1. JSP、Servlet、JavaBean技术的出现给我们构建强大的企业应用系统提供了可能。但用这些技术构建的系统非常的繁乱。

2. 基于Struts开发的应用:

不用再考虑公共问题

专心在业务实现上

结构统一,易于学习、维护

新手也可写出好程序

 

为什么要用spring

Spring是一个轻量级的IOC和AOP框架。

 IOC(控制反转)意味着将你设计好的类交给系统去控制,而不是在你的类内部控制。这称为控制反转

 AOP(面向切面),它将那些影响多个类的行为封装到可重用的模块中,面向对象是把问题从同类事物中抽象出来,面向切面是把问题从不同类问题中抽象出来。

 

1. hibernate中get()与load()区别

 请注意如果没有匹配的数据库记录,load()方法可能抛出无法恢复的异常(unrecoverable exception)。如果类的映射使用了代理(proxy),load()方法会返回一个未初始化的代理,直到你调用该代理的某方法时才会去访问数据库。若你希望在某对象中创建一个指向另一个对象的关联,又不想在从数据库中装载该对象时同时装载相关联的那个对象,那么这种操作方式就用得上的了。如果为相应类映射关系设置了batch-size,那么使用这种操作方式允许多个对象被一批装载(因为返回的是代理,无需从数据库中抓取所有对象的数据)。如果你不确定是否有匹配的行存在,应该使用get()方法,它会立刻访问数据库,如果没有对应的行,会返回null。

 

判断:使用save/persist一个对象时,便立即向数据库发送执行insert sql语句?

1) persist把一个瞬态的实例持久化,但是并"不保证"标识符被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时间。

2) persist"保证"当它在一个transaction外部被调用的时候并不触发一个Sql Insert,这个功能是很有用的。

3) save会立即执行Sql insert,不管是不是在transaction内部还是外部.

 

指出一下代码哪里错误使用了Hibernate。

背景简介:Board是一个实体类,id是它的主键,name和description是他的两个属性。BoardDao是Board实体的数据访问对象,BoardBo是业务对象,用户提交变更Board对象的请求,由Struts的BoardAction接收,调用BoardBo处理。HibernateUtil.currentSession()用于返回当前请求的Session对象。

//数据访问层代码:BoardDao.java 

publicBoardloadBoard(Longid){ 

Sessionsession=HibernateUtil.currentSession(); 

returnsession.load(Board.class,id); 

publicvoidupdateBoard(Boardboard){ 

Sessionsession=HibernateUtil.currentSession(); 

session.update(board); 

 

//业务对象层代码:BoardBo.java 

privateBoardDaoboardDao; 

publicvoidupdateBoard(Longid,Stringname,Stringdescription){ 

Boardboard=boardDao.loadBoard(id); 

board.setName(name); 

board.setDescription(description); 

boardDao.updateBoard(board); 

 

//Web控制器代码:BoardAction.java 

privateBoardBoBoardBo; 

publicActionForwardexecute( 

ActionMappingmapping, 

ActionFormform, 

HttpServletRequestrequest, 

HttpServletResponseresponse)throwsException{ 

Stringid=request.getParameter("id"); 

Stringname=request.getParameter("name"); 

Stringdescription=request.getParameter("description"); 

boardBo.updateBoard(id,name,description); 

returnmapping.findForward("update-success"); 

}

 public void updateBoard(Board board) {

Session session = HibernateUtil.currentSession();

 Transaction t=session.beginTransaction();

 session.update(board);

 t.commit();

 }

 

简单叙述一下Spring中BeanFactory与ApplicationContext的差别

使用BeanFactory从xml配置文件加载bean:

importorg.springframework.beans.factory.xml.XmlBeanFactory;

importorg.springframework.core.io.FileSystemResource;

 

publicclassXmlConfigWithBeanFactory{

 

publicstaticvoidmain(String[]args){

XmlBeanFactoryfactory=newXmlBeanFactory(newFileSystemResource(

"build/beans.xml"));

 

}

}

使用ApplicationConText从xml配置文件加载bean:

publicclassXmlConfigWithApplication{

 

publicstaticvoidmain(String[]args){

ApplicationContextapplication=newClassPathXmlApplicationContext(beans.xml"));

application.getBean("BeanName");

}

}

简而言之,BeanFactory提供了配置框架和基本的功能, 而 ApplicationContext为它增加了更强的功能,这些功能中的一些或许更加接近J2EE并且围绕企业级应用。一般来说,ApplicationContext是 BeanFactory的完全超集,任何BeanFactory功能和行为的描述也同样被认为适用于ApplicationContext

相对于BeanFactory而言,ApplicationContext 提供了以下扩展功能.

 (a) 国际化支持 (b) 资源访问

 (c) 事件传播 (d) 多实例加载

2. 写一段程序,使用springAPI读取classpath下的一个xml文件,并解析

(1)Resource resource=new ClassPathResource("appcontext.xml");

 BeanFactory factory=new XmlBeanFactory(resource);

 

 (2)ClassPathXmlApplicationContext appcontext=new ClassPathXmlApplicationContext("appcontext.xml");

 BeanFactory factory=(BeanFactory)appcontext;

 

 

在hibernate中使用Integer做映射和使用int做映射之间有什么差别

Integer code和int code;的区别:

Integer是对象. code = null; 对象可以为空.

int 是普通类型, 不可能 = null.

根据你的数据库code是可以空的, 故应该映射成Integer.

你没理由hbm.xml里写Integer, 类里却写int

 

(1)使用Spring如何简化了Hibernate编码?

通过org.springframework.orm.hibernate3.support.HibernateDaoSupport类支持数据库操作,且封装了事务.

public class AccountDAO extends HibernateDaoSupport implements IAccountDAO{

 

(2)Spring如何与Struts集成?

<xml version="1.0" encoding="UTF-8">

<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd">

 

<struts-config>

 <data-sources />

 <form-beans >

 <form-bean name="regForm" type="demo.form.RegForm" />

 

 </form-beans>

 <global-exceptions />

 <global-forwards />

 <action-mappings >

 <action

 attribute="regForm"

 name="regForm"

 path="/reg"

 scope="request"

 type="org.springframework.web.struts.DelegatingActionProxy">

 <forward name="ok" path="/ok.jsp" />

 </action>

 </action-mappings>

 

 <message-resources parameter="demo.ApplicationResources" />

 <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">

 <set-property property="contextConfigLocation" value="/WEB-INF/classes/applicationContext.xml" />

 </plug-in>

</struts-config>

 

如何使用Spring2.0实现声明式事务?

<!--通用事务管理器-->

<bean id="TransactionManager"

 class="org.springframework.orm.hibernate3.HibernateTransactionManager">

 <property name="sessionFactory" ref="sessionFactory" />

</bean>

 

<!--声明一个通知,用以指出要管理哪些事务方法及如何管理-->

<tx:advice id="txAdvice" transaction-manager="TransactionManager">

 <tx:attributes>

 <!-- 对get/load/search开头的方法要求只读事务 -->

 <tx:method name="get*" propagation="SUPPORTS"

 read-only="true" />

 <tx:method name="load*" propagation="SUPPORTS"

 read-only="true" />

 <tx:method name="search*" propagation="SUPPORTS"

 read-only="true" />

 <!-- 对其它方法要求事务 -->

 <tx:method name="*" propagation="REQUIRED" />

 </tx:attributes>

</tx:advice>

 

<!--声明一个config,用以将通知和目标业务类关联起来-->

<aop:config>

 <!-- 添加事务支持,因为前面配置的transactionManager是专对Hibernate的事务管理器-->

 <aop:pointcut id="bizMethods" expression_r_r="execution(* demo.*.*(..))" />

 <!-- 织入 -->

 <aop:advisor advice-ref="txAdvice" pointcut-ref="bizMethods" />

</aop:config>

 

(4)依赖注入的好处是?

程序可扩展性更强;

利于并行开发;

 

(5)Spring怎么实现依赖注入?

<xml version="1.0" encoding="UTF-8">

<beans

 xmlns="http://www.springframework.org/schema/beans"

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

 

 <bean id="userdao" class="demo.dao.UserDAO"/>

 

 <bean id="usermanager" class="demo.biz.UserManager">

  <property name="userdao" ref="userdao"/>

 </bean>

</beans>

 

(6)“面向方面编程”的好处是?

将程序中涉及的公共问题集中解决

 

(7)和SQL相比,HQL有哪些特点?

HQL是面向对象的查询语言。select Fw表示查询Fw对象

 

(8)如何配置单向多对一关联?

<class name="Jd" table="TBL_JD">

 <id name="jdid" column="jdid" type="long">

 <generator class="identity" />

 </id>

 <property name="jdname" column="jd" type="string" />

 <many-to-one name="qx" class="Qx" column="qxid" />

</class>

 

(9)如何配置单向一对多关联?

<class name="Qx" table="TBL_QX">

 <id name="qxid" column="qxid" type="long">

 <generator class="native" />

 </id>

 <property name="qxname" column="qx" type="string" />

 <set name="jds" >

 <key column="qxid" />

 <one-to-many class="Jd" />

 </set>

</class>

(10)如何配置双向一对多关联?

<class name="Jd" table="TBL_JD">

 <id name="jdid" column="jdid" type="long">

 <generator class="identity" />

 </id>

 <property name="jdname" column="jd" type="string" />

 <many-to-one name="qx" class="Qx" column="qxid" />

</class>

<class name="Qx" table="TBL_QX">

 <id name="qxid" column="qxid" type="long">

 <generator class="native" />

 </id>

 <property name="qxname" column="qx" type="string" />

 <set name="jds" >

 <key column="qxid" />

 <one-to-many class="Jd" />

 </set>

</class>

 对于Hibernate,面试官最想知道的无非是以下总结这这十多个问题,每个问题都有详细的答案,如果都完全掌握以下的这些问题,那面试时问及Hibernate你还用怕什么呢?让自信伴随着你第一次冲刺吧!

一、简述 Hibernate 和 JDBC 的区别、优缺点?

JDBC与Hibernate在性能上相比,JDBC灵活性有优势。而Hibernate在易学性,易用性上有些优势。当用到很多复杂的多表联查和复杂的数据库操作时,JDBC有优势。
相同点:
◆两者都是JAVA的数据库操作中间件。

◆两者对于数据库进行直接操作的对象都不是线程安全的,都需要及时关闭。

◆两者都可以对数据库的更新操作进行显式的事务处理。

不同点:
◆使用的SQL语言不同:JDBC使用的是基于关系型数据库的标准SQL语言,Hibernate使用的是HQL(Hibernate query language)语言

◆操作的对象不同:JDBC操作的是数据,将数据通过SQL语句直接传送到数据库中执行,Hibernate操作的是持久化对象,由底层持久化对象的数据更新到数据库中。

◆数据状态不同:JDBC操作的数据是“瞬时”的,变量的值无法与数据库中的值保持一致,而Hibernate操作的数据是可持久的,即持久化对象的数据属性的值是可以跟数据库中的值保持一致的。

JDBC与Hibernate读取性能

1、JDBC仍然是最快的访问方式,不论是Create还是Read操作,都是JDBC快。

2、Hibernate使用uuid.hex构造主键,性能稍微有点损失,但是不大。

3、Create操作,JDBC在使用批处理的方式下速度比Hibernate快,使用批处理方式耗用JVM内存比不使用批处理方式要多得多。

4、读取数据,Hibernate的Iterator速度非常缓慢,因为他是每次next的时候才去数据库取数据,这一点从观察任务管理器的java进程占用内存的变化也可以看得很清楚,内存是几十K几十K的增加。

5、读取数据,Hibernate的List速度很快,因为他是一次性把数据取完,这一点从观察任务管理器的java进程占用内存的变化也可以看得很清楚,内存几乎是10M的10M的增加。

6、JDBC读取数据的方式和Hibernate的List方式是一样的(这跟JDBC驱动有很大关系,不同的JDBC驱动,结果会很不一样),这 从观察java进程内存变化可以判断出来,由于JDBC不需要像Hibernate那样构造一堆Cat对象实例,所以占用JVM内存要比 Hibernate的List方式大概少一半左右。

7、Hibernate的Iterator方式并非一无是处,它适合于从大的结果集中选取少量的数据,即不需要占用很多内存,又可以迅速得到结果。另外Iterator适合于使用JCS缓冲。

附加说明:实际上,不管CMP,Hibernate,JDO等等,所有的ORM都是对JDBC的封装,CMP则是一个重量级封装,JDO中度封 装,Hibernate是轻量级的封装。从理论上来说,ORM永远也不可能比JDBC性能好。就像任何高级语言的运行性能永远也不会好过汇编语言一个道 理。

对于Create和Update操作来说,由于普通的Java程序员未必会使用JDBC的Batch的功能,所以Hibernate会表现出超过JDBC的运行速度。

对于Read的操作来说,ORM普遍都会带有双层缓冲,即PrepreadStatement缓冲和ResultSet缓冲,而JDBC本身没有缓 冲机制,在使用连接池的情况下,一些连接池将会提供PrepreadStatement缓冲,有的甚至提供ResultSet缓冲,但是普遍情况 下,Java程序员一般都不会考虑到在写JDBC的时候优化缓冲,而且这样做也不太现实,所以在某些情况下,ORM会表现出超过JDBC的Read速度。

 

二、Hibernate三种状态的区分;

对于Hibernate,它的对象有三种状态,transient、persistent、detached
◆transient:瞬态或者自由态(new Data("没关联到Session前"),该po的实例和session没有关联,该po的实例处于transient)
◆persistent:持久化状态(和数据库中记录相射的Po实例,即数据库表中有条记录是对应于这个对象的。它的状态是persistent, 通过get和load等得到的对象都是persistent)
◆detached:脱管状态或者游离态
(1)当通过get或load方法得到的po对象它们都处于persistent,但如果执行delete(po)时(但还没执行事务),该 po状态就处于detached, (表示和session脱离关联),因delete而变成游离态可以通过save或saveOrUpdate()变成持久态
(2)当一个session执行close()或clear()、evict()之后,session缓存中的persistent的po对象也变成detached,此时持久对象会变成脱管对象,此时该对象虽然具有数据库识别值,但它已不在HIbernate持久层的管理之下。

 

三、hibernate中的update()和saveOrUpdate()的区别?

(1)update() 更新,没有主键会报错的,saveOrUpdate() 保存或更新, 没有主键就执行插入。
(2)Update:是对暂态(transient )或是只是脱管(detached)的更新操作,对于暂态对象的更新操作通常不产生效果,对于脱 管对象是做了同步的操作,即数据库的数据发生变化并且对象状态也成为托管对象
 SaveOrUpdate : 也是对暂态(transient )或是只是脱管(detached)的进行操作,至于是插入还是更新,则要根据(identifier)id 中指定的一些具体条件来分析,如果对象没有持久化标识(identifier)属性,对其调用save() ,否则update() 这个对象 。
(3)如果该po对象已经在本session中持久化了,在本session中执行saveOrUpdate(po)不做任何事
如果savaOrUpdate(给定id的新po)与另一个与本session关联的po对象拥有相同的持久化标识(identifier),抛出一个NonUniqueObjectException异常 :a different object with the same identifier value was already associated with the session。

 

四、Hibernate.update()和merge()区别?

前面说过update,基本merge和update一样。但如果session中存在相同持久化标识(identifier)的实例,用用户给出的对象覆盖session已有的持久实例
(1)当我们使用update的时候,执行完成后,会抛出异常
(2)但当我们使用merge的时候,把处理自由态的po对象A的属性copy到session当中处于持久态的po的属性中,执行完成后原来是持久状态还是持久态,而我们提供的A还是自由态。

 

五、Hibernate update和flush区别?

Hibernate update操作的是在自由态或脱管状态(因session的关闭而处于脱管状态)的对象,而flush是操作的在持久状态的对象。

默认情况下,一个持久状态的对象的改动(包含set容器)是不需要update的,只要你更改了对象的值,等待Hibernate flush就自动更新或保存到数据库了。
(1) 调用某些查询的和手动flush(),session的关闭、SessionFactory关闭结合。get()一个对象,把对象的属性进行改变,把资源关闭。
(2)transaction commit的时候(包含了flush) 。

 

六、Hibernate session的load()和get()的区别?

1:如果你使用load方法,hibernate认为该id对应的对象(数据库记录)在数据库中是一定存在的,所以它可以放心的使用,它可以放心的使用代理来延迟加载该对象。在用到对象中的其他属性数据时才查询数据库,但是万一数据库中不存在该记录,那没办法,只能抛异常,所说的load方法抛异常是指在使用该对象的数据时,数据库中不存在该数据时抛异常,而不是在创建这个对象时。由于session中的缓存对于hibernate来说是个相当廉价的资源,所以在load时会先查一下session缓存看看该id对应的对象是否存在,不存在则创建代理。所以如果你知道该id在数据库中一定有对应记录存在就可以使用load方法来实现延迟加载。 对于get方法,hibernate会确认一下该id对应的数据是否存在,首先在session缓存中查找,然后在二级缓存中查找,还没有就查数据库,数据库中没有就返回null(网上有很多误解以为get就马上去数据库查找根本不先查session那是不正确的,不想信你就去做下试验便知)。

2、“get()永远只返回实体类”,但实际上这是不正确的,get方法如果在session缓存中找到了该id对应的对象,如果刚好该对象前面是被代理过的,如被load方法使用过,或者被其他关联对象延迟加载过,那么返回的还是原先的代理对象,而不是实体类对象,如果该代理对象还没有加载实体数据(就是id以外的其他属性数据),那么它会查询二级缓存或者数据库来加载数据,但是返回的还是代理对象,只不过已经加载了实体数据。

3、再注重说明get方法首先查询session缓存,没有的话查询二级缓存,最后查询数据库;反而load方法创建时首先查询session缓存,没有就创建代理,实际使用数据时才查询二级缓存和数据库。

总之对于get和load的根本区别,一句话,hibernate对于load方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,如果在使用过程中发现了问题,只能抛异常;而对于get方法,hibernate一定要获取到真实的数据,否则返回null。

 

七、Hibernate List和Iterator方式的比较

(1)、List方式是1次性把所有的数据全部取到内存中,构造一个超大的结果集,主要的时间开销是这一步,这一步的时间开销要远远超过JDBC和 Iterator方式下构造结果集的时间开销,并且内存开销也很惊人;而对结果集的遍历操作,速度则是非常的惊人(经过测试,30万记录的内 存遍历不到100ms,由于这一步不受JDBC影响,因此结果可信)。因此,List方式适合于对结果集进行反复多次操作的情况,例如分页显示,往后往前 遍历,跳到第一行,跳到最后一行等等。

(2)、Iterator方式只取记录id到内存中,并没有把所有数据取到内存中,因此构造结果集的时间开销很小,比JDBC和List方式都要少,并且内 存开销也小很多。而对结果集的遍历的操作的时候,Iterator仍然要访问数据库,所有主要的时间开销都花在这里。因此,Iterator方式适合于只 对结果集进行1次遍历操作的情况,并且Iterator方式特别适合于从超大结果集中取少量数据,这种情况Iterator性能非常好。

 

八、hibernate的inverse属性的作用?

在Hibernate中,术语inverse是反转的意思,在关联关系中,inverse="false"为主控方,由主控方负责维护对象的关联关系。
inverse 决定是否把对对象中集合的改动反映到数据库中,所以inverse只对集合起作用,也就是只对one-to-many或many-to-many有效(因 为只有这两种关联关系包含集合,而one-to-one和many-to-one只含有关系对方的一个引用,注意一般只在双向关联时才有需要设置inverse)。
(1)、一对多:
通常会在的one一方放弃对多的关系的维护,这样效率会高起来(如老师记住每位学生是件困难的事情,效率是很低的,所以干脆就不记了,这关系由学生来维护,学生记住一位老师是很容易)
 所以应该在一方的设置 inverse=true ,多的一方设置 inverse=false(多的一方也可以不设置inverse属性,因为默认值是false),这说明关联关系由多的一方来维护。
如果要一方维护关系,就会使在插入或是删除"一"方时去update"多"方的每一个与这个"一"的对象有关系的对象。
而如果让"多"方面维护关系时就不会有update操作,因为关系就是在多方的对象中的,直指插入或是删除多方对象就行了。
显然这样做的话,会减少很多操作,提高了效率。
注:单向one-to-many关联关系中,不可以设置inverse="true",因为被控方的映射文件中没有主控方的信息。

(2)、多对多: 属性在独立表中。inverse属性的默认值为false。在多对多关联关系中,关系的两端 inverse不能都设为false,即默认的情况是不对的,如果都设为false,在做插入操作时会导致在关系表中插入两次关系。也不能都设为 true,如果都设为true,任何操作都不会触发对关系表的操作。因此在任意一方设置inverse=true,另一方inverse=false。

 

九、hibernate的cascade属性的作用?

cascade属性的作用是描述关联对象进行操作时的级联特性。因此,只有涉及到关系的元素才有cascade属性。
具 有cascade属性的标记包括<many-to-one /> <one-to-one /> <any /> <set /><bag /> <idbag /> <list /> <array />
注意:<ont-to-many />和 <many-to-many />是用在集合标记内部的,所以是不需要cascade属性的。
级联操作:指当主控方执行某项操作时,是否要对被关联方也执行相同的操作。

 

 

十、各种关联关系下的lazy懒加载区别?

1、one-to-one懒加载
 一对一的懒加载并不常用,因为懒加载的目的是为了减少与数据库的交互,从而提高执行效率,而在一对一关系中,主表中的每一条数据只对应从表的一条数据库,就算都查询也不会增加多少交互的成本,而且主表不能有contrained=true,所以主表是不能懒加载的。但是从表可以有。
    实现此种懒加载必须在从对象这边同时满足三个条件:
    1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)
    2、Constrained = true ;
    3、fetch=select。

 注:当fetch设置为join时,懒加载就会失效。因为fetch的作用是抓取方式,他有两个值分别为select和join,默认值为select。即在设为join时,他会直接将从表信息以join方式查询到而不是再次使用select查询,这样导致了懒加载的失效。

2、one-to-many懒加载
    与one-to-one关联不同,对one-to-many而言,主表的每一条属性都会对应从表的多条数据,这个时候懒加载就显得非常有效了。比如一个部门里面有多个员工,如果没有懒加载,每查询这个部门的时候都会查询出多个员工,这会大大增加与数据库交互的成本。所以Hbernate默认的是加入懒加载的。这就是查询集合属性的时候返回的是一个PersistentIndexed*类型对象的原因。该对象其实就是一个代理对象。当然,可以在映射文件中通过将lazy属性设为假来禁用。
  Hibernate默认对one-to-many就是使用的懒加载,但用户也可以取消懒加载操作:
     一:设置lazy=”false”;
     二:设置fetch=”join”.

实现此种懒加载必须在从对象这边同时满足两个条件:
   1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)
    2、fetch=select。

3、many-to-one懒加载

此关联关系的懒加载和one-to-one的懒加载一样都是可要可不要的,因为对执行效率的提高都不是非常明显。虽然多对一与一对一关系方式相同,但是在Hibernate中多对一时,默认是进行懒加载的。另外有一点需要注意的是懒加载并不会区分集合属性里面是否有值,即使是没有值,他依然会使用懒加载。

实现此种懒加载必须在从对象这边同时满足两个条件
   1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)
    2、fetch=select

4、many-to-many懒加载

此关联关系的懒加载和one-to-many的懒加载一样对程序的执行效率的提高都是非常明显的。
   实现此种懒加载必须在从对象这边同时满足两个条件:
     1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)
     2、fetch=select

能够懒加载的对象都是被改过的代理对象,当相应的对象没有关闭时,访问这些懒加载对象的属性(getId和getClass除外)Hibernate会初始化这些代理,或用hibernate.initalize(proxy)来初始化代理对象;当关闭session后在访问懒加载的对象就会出现异常。

 

 

 

十一、hibernate中lazy的使用中的区别?

Lazy的有效期:只有在session打开的时候才有效;session关闭后lazy就没效了。

lazy策略可以用在:

◆ <class>标签上:可以取值true/false

◆<property>标签上,可以取值true/false,这个特性需要类增强

◆<set>/<list>等集合上,可以取值为true/false/extra

◆<one-to-one>/<many-to-one>等标签上,可以取值false/proxy/no-proxy

6.1 get和load的区别:

◆get不支持延迟加载,而load支持。

◆当查询特定的数据库中不存在的数据时,get会返回null,而load则抛出异常。

6.2 类(Class)的延迟加载:

◆设置<class>标签中的lazy="true",或是保持默认(即不配置lazy属性)

◆ 如果lazy的属性值为true,那么在使用load方法加载数据时,只有确实用到数据的时候才会发出sql语句;这样有可能减少系统的开销。
  注意:在class标签上配置的lazy属性不会影响到关联对象!!!

 

十二、iBatis与Hibernate有什么不同?

相同点:屏蔽jdbc api的底层访问细节,使用我们不用与jdbc api打交道,就可以访问数据。
jdbc api编程流程固定,还将sql语句与java代码混杂在了一起,经常需要拼凑sql语句,细节很繁琐。
ibatis的好处:屏蔽jdbc api的底层访问细节;将sql语句与java代码进行分离;提供了将结果集自动封装称为实体对象和对象的集合的功能,queryForList返回对象集合,用queryForObject返回单个对象;提供了自动将实体对象的属性传递给sql语句的参数。

Hibernate是一个全自动的orm映射工具,它可以自动生成sql语句,ibatis需要我们自己在xml配置文件中写sql语句,hibernate要比ibatis功能负责和强大很多。因为hibernate自动生成sql语句,我们无法控制该语句,我们就无法去写特定的高效率的sql。对于一些不太复杂的sql查询,hibernate可以很好帮我们完成,但是,对于特别复杂的查询,hibernate就很难适应了,这时候用ibatis就是不错的选择,因为ibatis还是由我们自己写sql语句。

 

 

十三、介绍一下Hibernate的二级缓存

 

按照以下思路来回答:(1)首先说清楚什么是缓存,(2)再说有了hibernate的Session就是一级缓存,即有了一级缓存,为什么还要有二级缓存,(3)最后再说如何配置Hibernate的二级缓存。
(1)缓存就是把以前从数据库中查询出来和使用过的对象保存在内存中(一个数据结构中),这个数据结构通常是或类似Hashmap,当以后要使用某个对象时,先查询缓存中是否有这个对象,如果有则使用缓存中的对象,如果没有则去查询数据库,并将查询出来的对象保存在缓存中,以便下次使用。下面是缓存的伪代码:
引出hibernate的第二级缓存,用下面的伪代码分析了Cache的实现原理

Java代码   收藏代码
  1. Dao  
  2. {  
  3.     hashmap map = new map();  
  4.     User getUser(integer id)  
  5.     {  
  6.         User user = map.get(id)  
  7.         if(user == null)  
  8.         {  
  9.             user = session.get(id);  
  10.             map.put(id,user);  
  11.         }  
  12.         return user;  
  13.     }  
  14. }  
  15.   
  16. Dao  
  17. {  
  18.     Cache cache = null  
  19.     setCache(Cache cache)  
  20.     {  
  21.         this.cache = cache  
  22.     }  
  23.      
  24.     User getUser(int id)  
  25.     {  
  26.         if(cache!=null)  
  27.         {  
  28.             User user = cache.get(id);  
  29.             if(user ==null)  
  30.             {  
  31.                 user = session.get(id);  
  32.                 cache.put(id,user);  
  33.             }  
  34.             return user;  
  35.         }  
  36.          
  37.         return session.get(id);  
  38.     }  
  39. }  

 
(2)Hibernate的Session就是一种缓存,我们通常将之称为Hibernate的一级缓存,当想使用session从数据库中查询出一个对象时,Session也是先从自己内部查看是否存在这个对象,存在则直接返回,不存在才去访问数据库,并将查询的结果保存在自己内部。由于Session代表一次会话过程,一个Session与一个数据库连接相关连,所以Session最好不要长时间保持打开,通常仅用于一个事务当中,在事务结束时就应关闭。并且Session是线程不安全的,被多个线程共享时容易出现问题。通常只有那种全局意义上的缓存才是真正的缓存应用,才有较大的缓存价值,因此,Hibernate的Session这一级缓存的缓存作用并不明显,应用价值不大。Hibernate的二级缓存就是要为Hibernate配置一种全局缓存,让多个线程和多个事务都可以共享这个缓存。我们希望的是一个人使用过,其他人也可以使用,session没有这种效果。

(3)二级缓存是独立于Hibernate的软件部件,属于第三方的产品,多个厂商和组织都提供有缓存产品,例如,EHCache和OSCache等等。在Hibernate中使用二级缓存,首先就要在hibernate.cfg.xml配置文件中配置使用哪个厂家的缓存产品,接着需要配置该缓存产品自己的配置文件,最后要配置Hibernate中的哪些实体对象要纳入到二级缓存的管理中。明白了二级缓存原理和有了这个思路后,很容易配置起Hibernate的二级缓存。扩展知识:一个SessionFactory可以关联一个二级缓存,也即一个二级缓存只能负责缓存一个数据库中的数据,当使用Hibernate 的二级缓存后,注意不要有其他的应用或SessionFactory来更改当前数据库中的数据,这样缓存的数据就会与数据库中的实际数据不一致。



说说Hibernate对象的三种状态

Hibernate对象有三种状态,分别是:临时态(Transient)、 持久态(Persistent)、游离态(Detached)。

临时状态:是指从对象通过new语句创建到被持久化之前的状态,此时对象不在Session的缓存中。

处在此状态的对象具备以下特点:

1,不在Session缓存中,不与任何Session实例相关联。

2,在数据库中没有与之对应的记录。

通常在下列情况下对象会进入临时状态:

1,通过new语句创建新对象。

2,执行delete()方法,对于游离状态的对象,delete()方法会将其与数据库中对应的记录删除;而对于持久化状态的对象,delete()方法会将其与数据库中对应的记录删除,并将其在Session缓存中删除。

例如:Object object = new Object();

此时object为临时状态,数据库中没有对应的数据,Session缓存中也没有相关联的实例。

 

持久化状态:是指对象被持久化到Session对象被销毁之前的状态,此时对象在Session的缓存中。

处在此状态的对象具备以下特点:

1,在Session缓存中,与Session实例相关联。

2,在数据库中有与之对应的记录。

3,Session在清理缓存的时候,会根据持久化对象的属性变化更新数据库。


通常在下列情况下对象会进入临时状态:

1,执行save()或saveOrUpdate()方法,使临时对象转变为持久化对象。

2,执行upda()或saveOrUpdate()方法,使游离对象转变为持久化对象。

3,执行load()或get()方法,返回的对象都是持久化对象。

4,执行find()方法,返回List集合中存放的都是持久化对象。

5,在允许级联保存的情况下,Session在清理缓存时会把与持久化对象关联的临时对象转变为持久化对象。

例如:Session session = factory.openSession();  object.setName("持久化对象"); session.save(object);

此时object对象为持久化对象,Session缓存中有相关联的实例,数据库中有相应的记录。

 

游离状态:是指从持久化对象的Session对象被销毁到该对象消失之前的状态,此时对象不在Session的缓存中。

处在此状态的对象具备以下特点:

1,不在Session缓存中,不与任何Session实例相关联。

2,在数据库中有与之对应的记录(前提是没有其他Session实例删除该条记录)。


通常在下列情况下对象会进入临时状态:

1,执行close()方法,将Session缓存清空,缓存中的所有持久化对象将转变成游离对象。

2,执行evict()方法,能从缓存中删除一个持久化对象,使之转变成游离对象。

例如:session.close(); 

此时上文的object对象为游离对象,Session缓存中没有有相关联的实例,数据库中有相应的记录。

三种状态里面,只有持久化状态在Session缓存中有相关联的实例,临时状态跟游离状态都没有。临时状态数据库里没有对应的记录,其他两种可能又记录,也可能没有记录。

引用:http://www.cnblogs.com/liushuijinger/p/3543750.html

 

 hibernate工作流程
(1)启动Hibernate
(2)构建Configuration实例,初始化实例中的所有变量:
Configuration cfg = Configuration.configure();
(3)加载hibernate.cfg.xml文件至cfg实例所分配的内存
(4)通过hibernate.cfg.xml文件 中格的mapping节点进行配置,并加载.hbm.xml文件至cfg实例中
(5)由cfg实例构建一个SessionFactory实例:
SessionFactory sf = cfg.buildSessionFactory();
(6)由上面得到的sf实例创建Session连接:
Session s = sf.openSession();
(7)由Session实例创建事务操作接口Transaction的一个实例:
Transaction tx = s.beginTransaction();
(8)通过Session接口提供的各种方法操作对数据库的访问
(9)提交数据库操作结果:
tx.commit();
(10)关闭Session连接:
s.close(); 


hibernate与mybatis的区别 性能差异 为什么
hibernate是全自动,他会自动生成所有SQL,调优不太方便,它的主要思想是orm,对象关系映射
mybatis是半自动,它需要配置SQL和resultmap,调优方便,它的主要思想是sqlmapping
hibernate有更好的数据库移植性,而且二级缓存优于ibatis
不考虑缓存的情况 hibernate的性能高于ibatis

 

Struts2工作原理
  在Struts2框架中的处理大概分为以下几个步骤 
  1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求 
  2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin) 
  3 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action 
  4 如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy 
  5 ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类 
  6 ActionProxy创建一个ActionInvocation的实例。 
  7 ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。 
  8 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper 
Struts2工作流程
  1、客户端浏览器发出HTTP请求.
  2、根据web.xml配置,该请求被FilterDispatcher接收
  3、根据struts.xml配置,找到需要调用的Action类和方法, 并通过IoC方式,将值注入给Aciton
  4、Action调用业务逻辑组件处理业务逻辑,这一步包含表单验证。
  5、Action执行完毕,根据struts.xml中的配置找到对应的返回结果result,并跳转到相应页面
  6、返回HTTP响应到客户端浏览器 
 

spring Mvc和struts的区别 性能差异 为什么
mvc开发效率高,mvc配置方便于struts
struts是类级别拦截,一个类对应一个request上下文,mvc是方法级别拦截,一个方法对应一个request上下文,mvc更容易实现restful
mvc设计思路:将整个处理流程规范化,将每个不同的请求分发到不同的组件,设计清晰,直观

mvc性能更好,struts使用标签库,ognl,值栈等功能会降低struts的性能,而且,struts会把每个请求封装到map里以供action使用,保证线程安全.

 
解释AOP
 aop面向切面编程,是oop的重要补充,可以在不修改原有业务逻辑的前提下,加入一些公共的模块,比如日志,权限验证,事物管理。
可以通过编程式或注解式的方式实现。
aop主要通过jdk反射机制和cglib类和包实现,具体看目标类的类型,如果是接口,则使用jdk反射机制的方式。 
 
解释IOC
 ioc本身是一种设计思想,通过ioc容器可以很轻易的得到我们想要的对象或实例,它会自动注入值生成对象,这就是一种控制反转。
ioc最重要的一点就是在程序运行的时候可以动态的向某个对象提供所它依赖对象的实例。这就是通过依赖注入实现的。
依赖注入就是通过反射机制实现的,反射机制可以在程序运行的时候,得到一个对象所属的类,得到一个类的成员变量和方法,动态的创建类对象,动态的调用对象的方法。
具体实现就是参考XMLbeanfactory,classpathXMLapplicationcontext,applicationcontext除了提供基本的ioc功能外,还提供国际化,jndi,外部应用事件 
 
解释rmi
rmi包括客户端和服务端,他是通过tcp/ip加端口的方式访问,
客户端主要通过rmiproxyfactorybean对客户端进行封装,生成代理对象,查询得到Rmi的stub对象,并通过stub对象发起相应的远程调用请求。
服务端主要是通过rmiserviceexport导出远程调用对象的引用,同时将导出的对象同注册器绑定供客户端查询。 
 
 ioc aop优缺点
IOC是解耦,提供一种构造对象的方式,使得一种功能能有多种实现,且不构成依赖。spring 的IOC的缺点:占用内存多、构造对象慢、启动慢。
springAOP是提供一种基于spring框架的切面编程企业级解决方案,虽然这个已经很强大,但是依然还是没有aspectj强大,比如:目前还不支持流程切面。织入慢执行效率低、不支持new关键字创建的对象的切入,必须使用bean factory织入。 
 
spring事物应用
应用场景,如何使用
 
spring上下文
Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。 
 
 AOP原理
 Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。下面我们来研究一下Spring如何使用JDK来生成代理对象,具体的生成代码放在JdkDynamicAopProxy这个类中
配置可以通过xml文件来进行,大概有四种方式:
1.        配置ProxyFactoryBean,显式地设置advisors, advice, target等
2.        配置AutoProxyCreator,这种方式下,还是如以前一样使用定义的bean,但是从容器中获得的其实已经是代理对象
3.        通过<aop:config>来配置
4.        通过<aop: aspectj-autoproxy>来配置,使用AspectJ的注解来标识通知及切入点

下面的问题是,代理对象生成了,那切面是如何织入的?
我们知道InvocationHandler是JDK动态代理的核心,生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法。而通过JdkDynamicAopProxy的签名我们可以看到这个类其实也实现了InvocationHandler,下面我们就通过分析这个类中实现的invoke()方法来具体看下Spring AOP是如何织入切面的。
主流程可以简述为:获取可以应用到此方法上的通知链(Interceptor Chain),如果有,则应用通知,并执行joinpoint; 如果没有,则直接反射执行joinpoint
这个方法执行完成后,Advised中配置能够应用到连接点或者目标类的Advisor全部被转化成了MethodInterceptor.
如果得到的拦截器链为空,则直接反射调用目标方法,否则创建
MethodInvocation,调用其proceed方法,触发拦截器链的执行 

猜你喜欢

转载自blog.csdn.net/huaidan1469/article/details/79669729