还剩64页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
面试题全集(下)Java源自这部分主要是开源Java EE框架方面的内容,包括hibernate MyBatisspring、Spring MVC等,由于Struts2已经是明日黄花,在这里就不探讨Struts2的面试题,假如须要了解相关内容,可以参考我的另一篇文章《Java面试题集(86-115)》此外,这篇文章还对企业应用架构、大型网站架构和应用服务器优化等内容进行了简洁的探讨,这些内容信任对面试会很有帮助
126、什么是ORM答:对象关系映射(Object-Relational Mapping,简称ORM)是一种为了解决程序的面对对象模型及数据库的关系模型互不匹配问题的技术;简洁的说,ORM是通过运用描述对象和数据库之间映射的元数据(在Java中可以用XML或者是注解),将程序中的对象自动长久化到关系数据库中或者将关系数据库表中的行转换成Java对象,其本质上就是将数据从一种形式转换到另外一种形式
127、长久层设计要考虑的问题有哪些?你用过的长久层框架有哪些?答所谓〃长久〃就是将数据保存到可掉电式存储设备中以便今后运用,简洁的说,就是将内存中的数据保存到关系型数据库、文件系统、消息队列等供应长久化支持的设备中长久层就是系统中专注于实现数据长久化的相对独立的层面长久层设计的目标包括-数据存储逻辑的分别,供应抽象化的数据访问接口-数据访问底层实现的分别,可以在不修改代码的状况下切换底层实现-资源管理和调度的分别,在数据访问层实现统一的资源调度(如缓存机制)-数据抽象,供应更面对对象的数据操作长久层框架有-Hibernate-MyBatis-TopLink-Guzz-jOOQ-Spring Data-ActiveJDBC128N Hibernate中SessionFactory是线程平安的吗?Session是线程平安的吗(两个线程能够共享同一个Session吗)?答:SessionFactory对应Hibernate的一,个数据存储的概念,它是线程平安的,可以被多个线程并发访问SessionFactory一般只会在启动的时候构建对于应用程序,最好将SessionFactory通过单例模式进行封装以便于访问Session是一个轻量级非线程平安的对象(线程间不能共享session),它表示及数据库进行交互的一个工作单元Session是由SessionFactory创建的,在任务完成之后它会被关闭Session是长久层服务对外供应的主Spring
2.x中针对WebApplicationContext新增了3个作用域,分别是request每次恳求都会创建一个新的Bean、session同一个Session共享同一个Bean,不同的Session运用不同的Bean和globalSession同一k个全局Session共享一个Bean说明单例模式和原型模式都是重要的设计模式一般状况下,无状态或状态不行变的类适合运用单例模式在传统开发中,由于DA0持有Connection这个非线程平安对象因而没有运用单例模式;但在Spring环境下,全部DA0类对可以采纳单例模式,因为Spring利用A0P和Java API中的ThreadLocal对非线程平安的对象进行了特殊处理ThreadLocal为解决多线程程序的并发问题供应了一种新的思路ThreadLocal,顾名思义是线程的一个本地化对象,当工作于多线程中的对象运用ThreadLocal维护变量时,ThreadLocal为每个运用该变量的线程安排一个独立的变量副本,所以每一个线程都可以独立的变更自己的副本,而不影响其他线程所对应的副本从线程的角度看,这个变量就像是线程的本地变量ThreadLocal类特别简洁好用,只有四个方法,能用上的也就是下面三个方法-void setTvalue设置当前线程的线程局部变量的值-T get获得当前线程所对应的线程局部变量的值-void remove删除当前线程中线程局部变量的值ThreadLocal是如何做到为每一个线程维护一份独立的变量副本的呢?在ThreadLocal类中有一个Map,键为线程对象,值是其线程对应的变量的副本,自己要模拟实现一个ThreadLocal类其实并不困难,代码如下所示import java.util.Collections;import java.util.HashMap;import java.util.Map;public classMyThreadLocalT{private MapThread,T map=Collections.synchronizedMapnew HashMapThread,T0;public voidsetT newValue{map.putThread.currentThread,newValue;public Tget{return map.getThread.currentThread;public voidremove{map.removeThread.currentThread;
148、说明一下什么叫AOP面对切面编程?答AOP Aspect-Oriented Programming指一种程序设计范型,该范型以一种称为切面aspect的语言构造为基础,切面是一种新的模块化机制,用来描述分散在对象、类或方法中的横切关注点crosscutting concern
149、你是如何理解〃横切关注〃这个概念的?答〃横切关注〃是会影响到整个应用程序的关注功能,它跟正常的业务逻辑是正交的,没有必定的联系,但是几乎全部的业务逻辑都会涉及到这些关注功能通常,事务、日志、平安性等关注就是应用中的横切关注功能
150、你如何理解A0P中的连接点Joinpoint、切点Pointcut、增加Advice、引介Introduction、织入Weaving、切面Aspect这些概念?答a.连接点Joinpoint程序执行的某个特定位置如某个方法调用前、调用后,方法抛出异样后一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点Spring仅支持方法的连接点b.切点Pointcut假如连接点相当于数据中的记录,那么切点相当于查询条件,一个切点可以匹配多个连接点Spring AOP的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点c.增加Advice:增加是织入到目标类连接点上的一段程序代码Spring供应的增加接口都是带方位名的,如BeforeAdvice AfterReturningAdviceThrowsAdvice等很多资料上将增加译为“通知”,这明显是个词不达意的翻译,让很多程序员困惑了许久说明Advice在国内的很多书面资料中都被翻译成〃通知〃,但是很明显这个翻译无法表达其本质,有少量的读物上将这个词翻译为〃增加〃,这个翻译是对Advice较为精确的诠释,我们通过AOP将横切关注功能加到原有的业务逻辑上,这就是对原有业务逻辑的一种增加,这种增加可以是前置增加、后置增加、返回后增加、抛异样时增加和包围型增加d.引介(Introduction)引介是一种特殊的增加,它为类添加一些属性和方法这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类e.织入(Weaving)织入是将增加添加到目标类具体连接点上的过程,A0P有三种织入方式
①编译期织入须要特殊的Java编译期(例如AspectJ的ajc);
②装载期织入要求运用特殊的类加载器,在装载类的时候对类进行增加;
③运行时织入在运行时为目标类生成代理实现增加Spring采纳了动态代理的方式实现了运行时织入,而AspectJ采纳了编译期织入和装载期织入的方式f.切面(Aspect)切面是由切点和增加(引介)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义补充代理模式是GoF提出的23种设计模式中最为经典的模式之一,代理模式是对象的结构模式,它给某一个对象供应一个代理对象,并由代理对象限制对原对象的引用简洁的说,代理对象可以完成比原对象更多的职责,当须要为原对象添加横切关注功能时,就可以运用原对象的代理对象我们在打开Office系列的Word文档时,假如文档中有插图,当文档刚加载时,文档中的插图都只是一个虚框占位符,等用户真正翻到某页要查看该图片时,才会真正加载这张图,这其实就是对代理模式的运用,代替真正图片的虚框就是一个虚拟代理;Hibernate的load方法也是返回一个虚拟代理对象,等用户真正须要访问对象的属性时,才向数据库发出SQL语句获得真实对象下面用一个找枪手代考的例子演示代理模式的运用/***参考人员接口*©author骆昊**/public interfaceCandidate{/***答题*/public voidanswerTheQuestions;/***懒学生*©author骆昊**/public classLazyStudent implementsCandidate{private Stringname;//姓名public LazyStudentStringname{this.name=name;}©Overridepublic voidanswerTheQuestions{//懒学生只能写出自己的名字不会答题System,out.printin〃姓名〃+name;/***枪手*©author骆昊**/public classGunman implementsCandidate{private Candidatetarget;//被代理对象public GunmanCandidatetarget{this,target二target;}©Overridepublic voidanswerTheQuestions{//枪手要写上代考的学生的姓名target.answerTheQuestions;//枪手要帮助懒学生答题并交卷System,out.printin〃奋笔疾书正确答案〃;System,out.printin〃交卷〃;public classProxyTest1{Candidate c二new Gunmannew LazyStudent〃王小二〃;c.answerTheQuestions;说明从JDK
1.3起先,Java供应了动态代理技术,允许开发者在运行时创建接口的代理实例,主要包括Proxy类和InvocationHandler接口下面的例子运用动态代理为ArrayList编写一个代理,在添加和删除元素时,在限制台打印添加或删除的元素以及ArrayList的大小import java.lang,reflect.InvocationHandler;import java.lang,reflect.Method;import java.util.List;public classListProxyT implementsInvocationHandler{private ListTtarget;public ListProxyListTtarget{this,target=target;}©Overridepublic Object invoke Objectproxy,Method method,Object[]argsthrows Throwable{Object retVal=null;System,out.printinz/[z,+method.getName+〃:+args
[0]+〃]〃;retVal=method,invoketarget,args;System,out.printin,z[size=,/+target,size+〃]〃;return retVal;}import java.lang,reflect.Proxy;import java.util.ArrayList;import java.util.Lis t;public classProxyTest2{©SuppressWarnings uncheckedpublic static void mainString[]args{ListString list=new ArrayListString;Class clazz二list.getClass;ListProxyString myProxy二new ListProxyStringlist;ListString newList=ListStringProxy.newProxylnstanceclazz.getClassLoader,clazz.getlnterfaces,myProxy;newList.addapple;newList.addbanana;newList.addorange;newList.removebanana;说明运用Java的动态代理有一个局限性就是代理的类必须要实现接口,虽然面对接口编程是每个优秀的Java程序都知道的规则,但现实往往不尽如人意,对于没有实现接口的类如何为其生成代理呢?继承!继承是最经典的扩展已有代码实力的手段,虽然继承常常被初学者滥用,但继承也常常被进阶的程序员忽视CGLib采纳特别底层的字节码生成技术,通过为一个类创建子类来生成代理,它弥补了Java动态代理的不足,因此Spring中动态代理和CGLib都是创建代理的重要手段,对于实现了接口的类就用动态代理为其生成代理类,而没有实现接口的类就用CGLib通过继承的方式为其创建代理
151、Spring中自动装配的方式有哪些?答-no不进行自动装配,手动设置Bean的依靠关系-byName依据Bean的名字进行自动装配-byType依据Bean的类型进行自动装配-constructor类似于byType,不过是应用于构造器的参数,假如正好有一个Bean及构造器的参数类型相同则可以自动装配,否则会导致错误-autodetect假如有默认的构造器,则通过constructor的方式进行自动装配,否则运用byType的方式进行自动装配说明自动装配没有自定义装配方式那么精确,而且不能自动装配简洁属性(基本类型、字符串等),在运用时应留意
152、Spring中如何运用注解来配置Bean有哪些相关的注解?答首先须要在Spring配置文件中增加如下配置context:component-scan base-package=〃org.example/〉然后可以用©Component、@Controller、©Service、©Repository注解来标注须要由Spring IoC容器进行对象托管的类这几个注解没有本质区分,只不过©Controller通常用于限制器,©Service通常用于业务逻辑类,©Repository通常用于仓储类(例如我们的DAO实现类),一般的类用©Component来标注
153、Spring支持的事务管理类型有哪些?你在项目中运用哪种方式?答Spring支持编程式事务管理和声明式事务管理很多Spring框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念声明式事务管理要优于编程式事务管理,尽管在敏捷性方面它弱于编程式事务管理,因为编程式事务允许你通过代码限制业务事务分为全局事务和局部事务全局事务由应用服务器管理,须要底层服务器A支持(如WebLogic.WildFly等)局部事务和底层采纳的长久化方案有关,例如运用JDBC进行长久化时,须要运用Connetion对象来操作事务;而采纳Hibernate进行长久化时,须要运用Session对象来操作事务Spring供应了如下所示的事务管理器事务管理器实现类目标对象DataSourceTransactionManager注入DataSourceHibernateTransactionManager注入SessionFactoryJ doTran sac ti onManager管理J DO事务JtaTransactionManager运用JTA管理事务PersistenceBrokerTransactionManager管理Apache的OJB事务这些事务的父接口都是P1atformTransaetionManager Spring的事务管理机制是一种典型的策略模式,oP1at formT ransactionManager代表事务管理接口,该接口定义了三个方法,该接口并不知道底层如何管理事务,但是它的实现类必需供应getTransactionO方法(开启事务)、commit方法(提交事务)、rollback方法(回滚事务)的多态实现,这样就可以用不同的实现类代表不同的事务管理策略运用JTA全局事务策略时,须要底层应用服务器支持,而不同的应用服务器所供应的JTA全局事务可能存在细微环节上的差异,因此实际配置全局事务管理器是可能须要运用JtaTransactionManager的子类,如WebLogicJtaTransactionManager(Oracle的WebLogic服务器供应)、UowJ taTransactionManager(IBM的WebSphere服务器供应)等编程式事务管理如下所示xml version=〃
1.0encoding=UTF-8”〉beans xmlns=〃://springframework.org/schema/beans”xmlns:xsi=z/://w
3.org/2023/XMLSchema-instance xmlns:p=〃://springframework.org/schema/pz,xmlns:p=/,://springframework,org/schema/context,zxsi:schemaLocation=://springframework.org/schema/context://springframework,org/schema/context/spring-context.xsd〃context:component-scan base-package=com.jackfrued,,/bean id=propertyConfig〃class=,,org.springframework.beans,factory,config.PropertyPlaceholderConf igurerz,property name=〃location”〉valuejdbc.properties/value/property/beanbean id二〃dataSource class=〃org・apache mons.dbcp.BasieDataSourcez,property name=/zdriverClassNamez,value${db.driver}/value/propertyproperty name二〃url〃value${db.url}/value/propertyproperty name=username”〉value${db.username}/value〉/propertyproperty name=〃password”〉value${db.password/value要接口Session会延迟获得数据库连接也就是在须要的时候才会获得为了避开创建太多的session,可以运用ThreadLocal将session和当前线程绑定在一起,这样可以让同一个线程获得的总是同一个sessionHibernate3中SessionFactory的getCurrentSession方法就可以做到129Hibernate中Session的load和get方法的区分是什么?答主要有以下三项区分
①假如没有找到符合条件的记录,get方法返回null,load方法抛出异样
②get方法干脆返回实体类对象,load方法返回实体类对象的代理
③在Hibernate3之前,get方法只在一级缓存中进行数据查找,假如没有找到对应的数据则越过二级缓存,干脆发出SQL语句完成数据读取;load方法则可以从二级缓存中获得数据;从Hibernate3起先,get方法不再是对二级缓存只写不读,它也是可以访问二级缓存的说明对于load方法Hibernate认为该数据在数据库中肯定存在可以放心的运用代理来实现延迟加载,假如没有数据就抛出异样,而通过get方法获得的数据可以不存在
130、Session的save、updatemergelocksaveOrUpdate和persist方法分别是做什么的?有什么区分?答Hibernate的对象有三种状态瞬时态transient、长久态persistent和游离态detached,如第135题中的图所示瞬时态的实例可以通过调用save、persist或者saveOrUpdate方法变成长久态;游离态的实例可以通过调用update、saveOrUpdatelock或者replicate变成长久态save和persist将会引发SQL的INSERT语句,而update或merge会引发UPDATE语句save和update的区分在于一个是将瞬时态对象变成长久态,一个是将游离态对象变为长久态merge方法可以完成save和update方法的功能,它的意图是将新的状态合并到已有的长久化对象上或创建新的长久化对象对于persist方法,依据官方文档的说明
①persist方法把一个瞬时态的实例长久化,但是并不保证标识符被马上填入到长久化实例中,标识符的填入可能被推迟到flush的时间;
②persist方法保证当它在一个事务外部被调用的时候并不触发一个INSERT语句,当须要封装一个长会话流程的时候,persist方法是很有必要的;
③save方法不保证第
②条,它要返回标识符,所以它会马上执行INSERT语句,不管是在事务内部还是外部至于lock方法和update方法的区分,update方法是把一个已经更改过的脱管状态的对象变成长久状态;lock方法是把一个没有更改过的脱管状态的对象变成长久状态
131、阐述Session加载实体对象的过程答Session加载实体对象的步骤是
①Session在调用数据库查询功能之前,首先会在一级缓存中通过实体类型和主键进行查找,假如一级缓存查找命中且数据状态合法,则干脆返回;
②假如一级缓存没有命中,接下来Session会在当前NonExists记录相当于一个查询黑/property/beanbean id=〃jdbcTemplate class=/,org.springframework,jdbc.core.JdbcTemplate〃〉property name=,,dataSource,,ref bean=/,dataSource,z//property/bean!—JDBC事务管理器一bean id=z,transact ionManagerclass=,,org.springframework,jdbc.datasource.DataSourceTransactionManagerz,scope=singleton”〉property name=dataSource”〉ref bean二〃dataSource”//property/bean!—声明事务模板--bean id=,ztransactionTemplate,,class-^org.springfraniework.Iransaclion.support.Transact ionTemplatez,property name=〃transactionManager〃ref bean=transactionManager”//property/bean/beans package com.jackfrued.dao.impl;import org.springframework.beans,factory,annotation.Autowired;import org.spring framework,jdbc.core.JdbcTemplate;import com.jackfrued.dao.EmpDao;import com.jackfrued.entity.Emp;©Repositorypublic classEmpDaoImpl implementsEmpDao{©Autowiredprivate JdbcTemplatejdbcTemplate;©Overridepublic booleansaveEmp emp{String sql=insert intoemp values,,〃;return JdbcTemplate.update sql,emp.getTdO,emp.getName,emp.getBirt hday二二1;}package com.jackfrued.biz.impl;import org.springframework.beans,factory,annotation.Autowired;import org.spring framework,stereotype.Service;import org.springframework,transaction.Transaction Status;import org.springframework.transaction,support.TransactionCallbackWithou tResult;import org.springframework.transaction,support.TransactionTemplate;import com.jackfrued.biz.EmpService;import com.jackfrued.dao.EmpDao;import com.jackfrued.entity.Emp;©Servicepublic classEmpServicelmpl implementsEmpService{©Autowiredprivate TransactionTemplatetxTemplate;©Autowiredprivate EmpDaoempDao;©Overridepublic voidaddEmpfinal Empemp{txTemplate.executenew TransactionCallbackWithoutResult{©Overrideprotected voiddoInTransactionWithoutResultTransactionStatus txStatus{empDao.saveemp;}};声明式事务如下图所示,以Spring整合Hibernate3为例,包括完整的DAO和业务逻辑代码xml version=〃
1.0〃encoding二〃UTF-8〃?beans xmlns=〃://springframework,org/schema/beans,,xmlns:xsi=z/://w
3.org/2023/XMLSchema-instance”xmlns:p=/z://springframework.org/schema/pz,xmlns:context=〃://springframework.org/schema/context^xmlns:aop=gframework.org/schema/aop〃xmlns:tx=〃//springframework,org/schema/tx〃xsi:schemaLocation=
2.xsd://springframework,org/schema/tx/spring-tx-
3.
2.xsd〃!-配置由Spring IoC容器托管的对象对应的被注解的类所在的包—context:component-scan base-package=,zcom.jackfrued/z/!-配置通过自动生成代理实现AOP功能一aop:aspectj-autoproxy/!—配置数据库连接池DBCP—bean id=dataSource〃class=,,org.apache mons・dbcp・BasicDataSource”destroy-method=close”〉!-配置驱动程序类―property name=/,driverClassNanie//value=〃com・mysql.jdbc.Driver”/!-配置连接数据库的URL-property name二value=//jdbc:mysql://localhost:3306/myweb,z/!-配置访问数据库的用户名--〉property name二〃username value二〃root”/!-配置访问数据库的口令--property name=password value=”123456〃/!-配置最大连接数—property name=maxActive value=“150〃/!-配置最小空闲连接数property name二〃minldle value=5〃/!-配置最大空闲连接数~property name=maxldle value=〃20〃/!-配置初始连接数一property name=initialSize value=〃10〃/!-配置连接被泄露时是否生成日志--〉property name=〃logAbandoned〃value=true/!-配置是否删除超时连接--〉property name=/,removeAbandonedz/value二〃true”/!-配置删除超时连接的超时门限值(以秒为单位)--property name=,,removeAbandonedTimeout,zvalue=〃120〃/!配置超时等待时间(以毫秒为单位)property name=,,maxWait/,value=〃5000〃/!-配置空闲连接回收器线程运行的时间间隔(以毫秒为单位)-property name=/,timeBetweenEvictionRunsMillisz,value=”300000〃/!-配置连接空闲多长时间后(以毫秒为单位)被断开连接一property name=,,minEvictableldleTimeMi11isvalue=”60000〃//bean!一配置Spring供应的支持注解ORM映射的Hibernate会话工厂--bean id=sessionFactory”class=,/org.springframework,orm.hibernate
3.annotation.AnnotationSessionF actoryBean,z!--通过setter注入数据源属性--property name=dataSource ref=,,dataSourcez,/!—配置实体类所在的包--property name=packagesToScan value=〃com・jackfrued.entity”/!一配置Hibernate的相关属性一property name=/,hibernateProperties,,!—在项目调试完成后要删除show_sql和format_sql属性否则对性能有显著影响--value/value/property/bean!--配置Spring供应的Hibernate事务管理器--bean id=z,transactionManager,/class=〃org・springframework,orm.hibernate
3.HibernateTransactionManager,z!--通过setter注入Hibernate会话工厂--〉property name=sessionFactory“ref=/,sessionFactoryz,//bean!-配置基于注解配置声明式事务--tx:annotation-driven//beans package com.jackfrued.dao;import java.io.Serializable;import java.util.List;import com.jackfrued m.QueryBean;import com.jackfrued m.QueryResult;/***数据访问对象接口(以对象为单位封装CRUD操作)*©author骆昊**©param E实体类型*@param K实体标识字段的类型*/public interfaceBaseDao E,K extendsSerializable{/***新增*@param entity业务实体对象*©return增加胜利返回实体对象的标识*/public KsaveE entity;/***删除*@param entity业务实体对象*/public voiddeleteE entity;/***依据ID删除*@param id业务实体对象的标识*©return删除胜利返回true否则返回false*/public booleandeleteByIdK id;/***修改*@param entity业务实体对象*©return修改胜利返回true否则返回falsepublic voidupdateE entity;/***依据ID查找业务实体对象*@param id业务实体对象的标识*©return业务实体对象对象或null*/public EfindByIdK id;/***依据ID查找业务实体对象*@param id业务实体对象的标识*@param lazy是否运用延迟加载*©return业务实体对象对象*/public EfindByldK id,boolean lazy;/***查找全部业务实体对象*©return装全部业务实体对象的列表容器*/public ListEfindAll;/***分页查找业务实体对象*@param page页码*@param size页面大小*©return查询结果对象*/public QueryResultE findByPageint page,int size;/***分页查找业务实体对象*@param queryBean查询条件对象*@param page页码*@param size页面大小*@return查询结果对象*/public QueryResultE findByPageQueryBean queryBean,int page,int size;package com.jackfrued.dao;import java.io.Serializable;import java.util.List;名单,假如出现重复的无效查询可以快速做出推断,从而提升性能)中进行查找,假如NonExists中存在同样的查询条件,则返回null;
③假如一级缓存查询失败则查询二级缓存,假如二级缓存命中则干脆返回;
④假如之前的查询都未命中,则发出SQL语句,假如查询未发觉对应记录则将此次查询添加到Session的NonExists中加以记录,并返回null;5依据映射配置和SQL语句得到ResultSet,并创建对应的实体对象;6将对象纳入Session(一级缓存)的管理;7假如有对应的拦截器,则执行拦截器的nLoad方法;假如开启并设置了要运用二级缓存,则将数据对象纳入二级缓存;8
(9)返回数据对象
132、Query接口的list方法和iterate方法有什么区分?答
①list方法无法利用一级缓存和二级缓存(对缓存只写不读),它只能在开启查询缓存的前提下运用查询缓存;iterate方法可以充分利用缓存,假如目标数据只读或者读取频繁,运用iterate方法可以削减性能开销9list方法不会引起N+1查询问题,而iterate方法可能引起N+1查询问题说明关于N+1查询问题,可以参考CSDN上的一篇文章《什么是N+1查询》133Hibernate如何实现分页查询?答通过Hibernate实现分页查询,开发人员只须要供应HQL语句(调用Session的createQuery()方法)或查询条件(调用Session的createCriteriaO方法)、设置查询起始行数(调用Query或Criteria接口的setFirstResult()方法)和最大查询行数(调用Query或Criteria接口的setMaxResults()方法),并调用Query或Criteria接口的list()方法,Hibernate会自动生成分页查询的SQL语句
134、锁机制有什么用?简述Hibernate的悲观锁和乐观锁机制答有些业务逻辑在执行过程中要求对数据进行排他性的访问,于是须要通过一些机制保证在此过程中数据被锁住不会被外界修改,这就是所谓的锁机制Hibernate支持悲观锁和乐观锁两种锁机制悲观锁,顾名思义悲观的认为在数据处理过程中极有可能存在修改数据的并发事务(包括本系统的其他事务或来自外部系统的事务),于是将处理的数据设置为锁定状态悲观锁必需依靠数据库本身的锁机制才能真正保证数据访问的排他性,关于数据库的锁机制和事务隔离级别在《Java面试题大全(上)》中已经探讨过了乐观锁,顾名思义,对并发事务持乐观看法(认为对数据的并发操作不会常常性的发生),通过更加宽松的锁机制来解决由于悲观锁排他性的数据访问对系统性能造成的严峻影响最常见的乐观锁是通过数据版本标识来实现的,读取数据时获得数据的版本号,更新数据时将此版本号加1,然后和数据库表对应记录的当前版本号进行比较,假如提交的数据版本号大于数据库中此记录的当前版本号则更新数据,否则认为是过期数据无法更新Hibernate中通过Session的get()和load方法从数据库中加载对象时可以通过参数指定import com.jackfrued m.QueryBean;import com.jackfrued m.QueryResult;/***BaseDao的缺省适配器*©author骆昊**@param E实体类型*@param K实体标识字段的类型*/public abstractclass BaseDaoAdapterE,K extendsSerializable implementsBaseDaoE,K{©Overridepublic KsaveE entity{return null;}©Overridepublic voiddeleteE entity{}©Overridepublic booleandeleteByldK id{E entity=findByldid;if entity!=null{delete entity;return true;}return false;©Overridepublic voidupdateE entity{©Overridepublic EfindByIdK id{return null;}©Overridepublic EfindByIdK id,boolean lazy{return null;}©Overridepublic ListEfindAll{return null;©Overridepublic QueryResultEfindByPageint page,int size{return null;}©Overridepublic QueryResultEfindByPageQueryBean queryBean,int page,int sizereturn null;package com.jackfrued.dao;import java.io.Serializable;import java.lang.reflect.ParameterizedType;import java.util.ArrayList import java.util.Collections;import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.springframework,beans,factory,annotation.Autowired;import com.jackfrued m.HQLQueryBean;import com.jackfrued m.QueryBean;impo rtcom.jackfrued m.QueryResult;/***基于Hibernate的BaseDao实现类*©author骆昊*@param E实体类型*@param K主键类型*/@SuppressWarningsvalue={unchecked}public abstractclass BaseDaoHibernatelmpKE,K extendsSerializableextends BaseDaoAdapterE,K{@Autowiredprotected SessionFactorysessionFactory;private ClassentityClass;//业务实体的类对象private StringentityName;//业务实体的名字public BaseDaoHibernatelmpl{Parameter!zedType pt=ParameterizedType this.getClass.getGenericSu perclass;entityClass=Class pt.getActualTypeArguments
[0];entityName=entityClass.getSimpleName;}©Overridepublic KsaveE entity{return KsessionFactory.getCurrentSession.saveentity;©Overridepublic voiddeleteE entity{sessionFactory.getCurrentSession.deleteentity;}©Overridepublic voidupdateE entity{sessionFactory.getCurrentSession.updateentity;}©Overridepublic EfindByldK id{return findByldid,false;©Overridepublic EfindByldK id,boolean lazy{Session session=sessionFactory.getCurrentSession;return Elazy session.loadentityClass,id:session.get entityClass,id;}©Overridepublic ListEfindAll{return sessionFactory.getCurrentSession.createCriteriaentityClass.1ist;©Overridepublic QueryResultEfindByPageint page,int size{return newQueryResultEfindByllQLAndPage from〃+entityName,page,size,getCountByHQLselect count*from+entityName;}©Overridepublic QueryResultEfindByPageQueryBean queryBean,int page,int size{ifqueryBeaninstanceof HQLQueryBean{IIQLQueryBean hqlQueryBean二HQLQueryBean queryBean;return newQueryResultEf indByHQLAndPagehqlQueryBean.getQueryString,page,size,hql QueryBean.getParameters,getCountByHQLhqlQueryBean.getCountString,hqlQueryBean.getPa rameters;return null;/***依据HQL和可变参数列表进行查询*©param hql基于HQL的查询语句*@param params可变参数列表*©return持有查询结果的列表容器或空列表容器*/protected ListEfindByHQLString hql,Object...params{return this.findByHQLhql,getParamListparams;}/***依据HQL和参数列表进行查询*@param hql基于HQL的查询语句*@param params查询参数列表*©return持有查询结果的列表容器或空列表容器*/protected ListEfindByHQLString hql,List0bject params{ListE list=createQueryhql,params.list;return list!=nulllist.size0list:Collections.EMPTY_LIST;}/***依据HQL和参数列表进行分页查询*@param hql基于HQL的查询语句*@page页码*©size页面大小*@param params可变参数列表*©return持有查询结果的列表容器或空列表容器*/protected ListEfindByHQLAndPageString hql,int page,int size,Objec t...params{return this,findByHQLAndPagehql,page,size,getParamListparams;}/***依据HQL和参数列表进行分页查询*@param hql基于HQL的查询语句*@page页码*@size页面大小*@param params查询参数列表*©return持有查询结果的列表容器或空列表容器*/protected ListEfindByHQLAndPageString hql,int page,int size,ListObj ectparams{ListE list=createQueryhql,params.setFirstResultpage-1*size,setMaxResults size.list;return list!=nulllist,size0list:Collections.EMPTY_LIST;/***查询满意条件的记录数*@param hql基于HQL的查询语句*@param params可变参数列表*©return满意查询条件的总记录数*/protected longgetCountByHQLString hql,Object...params{return this.getCountByHQLhql,getParamListparams;}/***查询满意条件的记录数*@param hql基于HQL的查询语句*@param params参数列表容器*©return满意查询条件的总记录数*/protected longgetCountByHQLString hql,ListObject params{return LongcreateQueryhql,params.uniqueResult;//创建Hibernate查询对象Queryprivate QuerycreateQueryString hql,List0bject paramsQueryquery=sessionFactory.getCurrentSession.createQueryhql;forint i=0;iparams,size;i++{query.setParameteri,params,geti;}return query;}//将可变参数列表组装成列表容器private ListObjectgetParamListObject...params{ListObject paramList=new ArrayListO;ifparams!=null{forint i=0;iparams,length;i++{paramList.addparams[i];}}return paramList.size==0Collections.EMPTY LIST:paramList;}package com.jackfrued m;import java.util.List;/***查询条件的接口运用悲观锁;而乐观锁可以通过给实体类加整型的版本字段再通过XML或卿°”[011注解进行配置提示运用乐观锁会增加了一个版本字段,很明显这须要额外的空间来存储这个版本字段,奢侈了空间,但是乐观锁会让系统具有更好的并发性,这是对时间的节约因此乐观锁也是典型的空间换时间的策略
135、阐述实体对象的三种状态以及转换关系答最新的Hibernate文档中为Hibernate对象定义了四种状态原来是三种状态,面试的时候基本上问的也是三种状态,分别是瞬时态new,or transient、长久态managed,or persistent、游状态detached和移除态removed,以前Hibernate文档中定义的三种状态中没有移除态,如下图所示,就以前的Hibernate文档中移除态被视为是瞬时态•瞬时态当new一个实体对象后,这个对象处于瞬时态,即这个对象只是一个保存临时数据的内存区域,假如没有变量引用这个对象,则会被JVM的垃圾回收机制回收这个对象所保存的数据及数据库没有任何关系,除非通过Session的save、saveOrUpdateOpersistO merge方法把瞬时态对象及数据库关联,并把数据插入或者更新到数据库,这个对象才转换为长久态对象•长久态长久态对象的实例在数据库中有对应的记录,并拥有一个长久化标识ID对长久态对象进行delete操作后,数据库中对应的记录将被删除,那么长久态对象及数据库记录不再存在对应关系,长久态对象变成移除态可以视为瞬时态长久态对象被修变更更后,不会立刻同步到数据库,直到数据库事务提交游离态当Session进行了closeclearevict或flush后,实体对象从长久态变成游离态,对象虽然拥有长久和及数据库对应记录一样的标识值,但是因*©author骆昊**/public interfaceQueryBean{/***添加排序字段*@param fieldName用于排序的字段*@param asc升序还是降序*©return查询条件对象自身便利级联编程*/public QueryBeanaddOrderString fieldName,boolean asc;/***添加排序字段*@param available是否添加此排序字段*@param fieldName用于排序的字段*@param asc升序还是降序*©return查询条件对象自身便利级联编程*/public QueryBeanaddOrderboolean available,String fieldName,boolean asc;/***添加查询条件*©param condition条件*©param params替换掉条件中参数占位符的参数*©return查询条件对象自身便利级联编程*/public QueryBeanaddConditionString condition,Object...params;/***添加查询条件*@param available是否须要添加此条件*@param condition条件*@param params替换掉条件中参数占位符的参数*©return查询条件对象自身便利级联编程*/public QueryBeanaddConditionboolean available,String condition,Objec t...params;/***获得查询语句*©return查询语句*/public StringgetQueryString;/***获得查询记录数的查询语句*©return查询记录数的查询语句*/public StringgetCountStringO;/***获得查询参数*©return查询参数的列表容器*/public ListObjectgetParameters;package com.jackfrued m;import java.util.List;/***查询结果*©author骆昊**@param T泛型参数*/public classQueryResultT{private ListTresult;//持有查询结果的列表容器private long totalRecords;//查询到的总记录数/***构造器public QueryResult{/***构造器*@param result持有查询结果的列表容器*@param totalRecords查询到的总记录数*/public QueryResultListTresult,long totalRecords{this.result=result;this.totalRecords=totalRecords;public ListTgetResult{return result;}public voidsetResultListT result{this.result=result;}public longgetTotalRecords{return totalRecords;public voidsetTotalRecordslong totalRecords{this.totalRecords=totalRecords;}package com.jackfrued.dao;import com.jackfrued m.QueryResult;import com.jackfrued.entity.Dept;/***部门数据访问对象接口*©author骆昊**/public interfaceDeptDao extendsBaseDaoDept,Integer{/***分页查询顶级部门*@param page页石马*@param size页码大小*©return查询结果对象*/public QueryResultDeptfindTopDeptByPageint page,int size;package com.jackfrued.dao.impl;import java.util.List;import org.springframework,stereotype.Repository;import com.jackfrued m.QueryResult;import com.jackfrued.dao.BaseDaoIIibernatelmpl;import com.jackfrued.dao.DeptDao;import com.jackfrued.entity.Dept;©Repositorypublic classDeptDaoImpl extendsBaseDaoHibernatelmpKDept,Integer implementsDeptDao{private staticfinal StringHQL_FINDTOPDEPT=〃from Deptas dwhere d.su periorDeptis null〃;©Overridepublic QueryResultDeptfindTopDeptByPageint page,int size{ListDept list=findByHQLAndPageHQL_FIND_TOP_DEPT,page,size;longtotalRecords=getCountByHQLC selectcount*“+IIQL_FIND_TOP_DEPT;return newQueryResultOlist,totalRecords;package com.jackfrued m;importjava.util.List;*分页器*©author骆昊**@param T分页数据对象的类型*/public classPageBeanT{private staticfinal intDEFAUL INITPAGE=1;private staticfinal intDEFAULT_PAGE_SIZE=10;private staticfinal intDEFAULT_PAGE_COUNT=5;private ListTdata;//分页数据private PageRangepageRange;//页码范围private int totalPage;//总页数private int size;//页面大小private int currentPage;//当前页码private int pageCount//页码数量/***构造器*@param currentPage当前页码*@param size页码大小*@param pageCount页码数量*/public PageBeanintcurrentPage,int size,int pageCount{this.currentPage=currentPage0currentPage:1;this.size=size0size:DEFAULT PAGE_SIZE;this.pageCount=pageCount0size:DEFAULT_PAGE_COUNT;/***构造器*@param currentPage当前页码*@param size页码大小*/public PageBeanintcurrentPage,int size{thiscurrentPage,size,DEFAULT PAGECOUNT;/***构造器*©param currentPage当前页码*/public PageBeanintcurrentPage{thiscurrentPage,DEFAULT_PAGE_SIZE,DEFAULT_PAGE_COUNT;}/***构造器*/public PageBean{thisDEFAUL_INIT_PAGE,DEFAULT_PAGE_SIZE,DEFAULT_PAGE_COUNT;public ListTgetDataO{return data;}public intgetStartPage{return pageRange!=nullpageRange.getStartPage:1;}public intgetEndPage{return pageRange!=nullpageRange.getEndPage:1;public longgetTotalPagereturn totalPage;public intgetSize{return size;/***将查询结果转换为分页数据*@param queryResult查询结果对象public intgetCurrentPage{*/return currentPage;public voidtransferQueryResultQueryResultT queryResultlongtotalRecords=queryResult.getTotalRecords;data=queryResult.getResultOtotalPage=int totalRecords+size-1/size;totalPage=totalPage=0totalPage:Integer.MAX_VALUE;为对象已经从会话中清除掉,对象不在长久化管理之内,所以处于游离态也叫脱管态游离态的对象及临时状态对象是特别相像的,只是它还含有长久化标识提示关于这个问题,在Hibernate的官方文档中有更为具体的解读
136、如何理解Hibernate的延迟加载机制?在实际应用中,延迟加载及Session关闭的冲突是如何处理的?答延迟加载就是并不是在读取的时候就把数据加载进来,而是等到运用时再加载Hibernate运用了虚拟代理机制实现延迟加载,我们运用Session的load方法加载数据或者一对多关联映射在运用延迟加载的状况下从一的一方加载多的一方,得到的都是虚拟代理,简洁的说返回给用户的并不是实体本身,而是实体对象的代理代理对象在用户调用getter方法时才会去数据库加载数据但加载数据就须要数据库连接而当我们把会话关闭时,数据库连接就同时关闭了延迟加载及session关闭的冲突一般可以这样处理1关闭延迟加载特性这种方式操作起来比较简洁,因为Hibernate的延迟加载特性是可以通过映射文件或者注解进行配置的,但这种解决方案存在明显的缺陷首先,出现〃no sessionorsession wasclosed〃通常说明系统中已经存在主外键关联,假如去掉延迟加载的话,每次查询的开销都会变得很大2在session关闭之前先获得须要查询的数据,可以运用工具方法Hibernate.islnitialized推断对象是否被加载,假如没有被加载则可以运用Hibernate,initialize方法加载对象3运用拦截器或过滤器延长Session的生命周期直到视图获得数据Spring整合Hibernate供应的OpenSessionlnViewFilter和OpenSessionlnViewInterceptor就是这种做法
137、举一个多对多关联的例子,并说明如何实现多对多关联映射答:例如商品和订单、学生和课程都是典型的多对多关系可以在实体类上通过刨lanyToMany注解配置多对多关联或者通过映射文件中的和标签配置多对多关联,但是实际项目开发中,很多时候都是将多对多关联映射转换成两个多对一关联映射来实现的
138、谈一下你对继承映射的理解答继承关系的映射策略有三种1每个继承结构一张表table perclass hierarchy,不管多少个子类都用一张表2每个子类一张表table persubclass,公共信息放一张表,特有信息放单独的表3每个具体类一张表table perconcrete class,有多少个子类就有多少张表第一种方式属于单表策略,其优点在于查询子类对象的时候无需表连接,查询速度快,适合多态查询;缺点是可能导致表很大°后两种方式属于多表策略,其优点在于数据存储紧凑,其缺点是须要进行连接查询,不适合多态查询
139、简述Hibernate常见优化策略答这个问题应当挑自己运用过的优化策略回答,常用的有
①制定合理的缓存策略二级缓存、查询缓存this.pageRange=new PageRangepageCount,currentPage,totalPage;package com.jackfrued m;/***页码范围*©author骆昊**/public classPageRange{private intstartPage;//起始页码private intendPage;//终止页码/***构造器*@param pageCount总共显示几个页码*@param currentPage当前页码*@param totalPage总页数*/public PageRangeintpageCount,intcurrentPage,inttotalPage{startPage=currentPage-pageCount-1/2;endPage=currentPage+pageCount/2;if startPage1{startPage=1;endPage=totalPagepageCountpageCount:totalPage;}if endPagetotalPage{endPage=totalPage;startPage二endPage-pageCount0endPage-pageCount+1:1;}}/***获得起始页页码*©return起始页页码*/public intgetStartPage{return startPage;/***获得终止页页码*©return终止页页码*/public intgetEndPagepackage com.jackfrued.biz;import com.jackfrued m.PageBean;import com.jackfrued.entity.Dept;/***部门业务逻辑接口*©author骆昊**/public interfaceDeptService{/***创建新的部门*@param department部门对象*©return创建胜利返回true否则返回false*/public booleancreateNewDepartmentDept department;/***删除指定部门*@param id要删除的部门的编号*©return删除胜利返回true否则返回falsepublic booleandeleteDepartmentInteger id;/***分页获得顶级部门*@param page页不马*@param size页码大小*©return部门对象的分页器对象*/public PageBeanDeptgetTopDeptByPageint page,int size;package com.jackfrued.biz.impl;import org.springframework.beans,factory,annotation.Autowired;importotype.Servi ce;importorg.springframework,transaction,annotation.Transactional;import com.jackfrued.biz.DcptService;import com.jackfrued m.PageBean;import com.jackfruedm.QueryResult;import com.jackfrued.dao.DeptDao;import com.jack frued.entity.Dept;@Service@Transactional//声明式事务的注解public classDeptServicelmpl implementsDeptService{@Autowiredprivate DeptDaodeptDao;©Overridepublic booleancreateNewDepartmontDept department{return deptDao.savedepartment!=null;}©Overridepublic booleandeleteDepartmentInteger id{return deptDao.deleteByldid;}©Overridepublic PageBeanDeptgetTopDeptByPageint page,intsize{QueryResultDept queryResult=deptDao.findTopDeptByPagepage,size;PageBeanDept pageBean二new PageBeanOpage,size;pageBean.transferQueryResultqueryResult;return pageBean;}
154、如何在Web项目中配置Spring的loC容器?答:假如须要在Web项目中运用Spring的loC容器,可以在Web项目配置文件web.xml中做出如下配置context-paramparam-namecontextConfigLocation/param-nameparam-valuec1asspath:applicationContext.xml/param-value/context-paramlistener〈listener-class〉/listener-class/listener
155、如何在Web项目中配置Spring MVC答要运用Spring MVC须要在Web项目配置文件中配置其前端限制器DispatcherServlet,如下所示web-appservletservlet-nameexample/servlet-name〈servlet-class〉/servlet-classload-on-startupK/load-on-startup/servletservlet-mappingservlet-nameexample/servlet-name〈ur『pattern〉*.html/url-pattern/servlet-mapping〉/web-app说明上面的配置中运用了*.html的后缀映射,这样做一方面不能够通过URL推断采纳了何种服务器端的技术,另一方面可以欺瞒搜寻引擎,因为搜寻引擎不会搜寻动态页面,这种做法称为伪静态化
156、Spring MVC的工作原理是怎样的?答Spring MVC的工作原理如下图所示:
①客户端的全部恳求都交给前端限制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的恳求
②DispatcherServlet收到恳求后,将依据恳求的信息(包括URL、协议方法、恳求头、恳求参数、Cookie等)以及HandlerMapping的配置找到处理该恳求的Handler(任何一个对象都可以作为恳求的Handler)
③在这个地方Spring会通过IlandlerAdapter对该处理器进行封装
④HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用
⑤Handler完成对用户恳求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息
⑥ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作
⑦当得到真正的视图对象后,DispatcherServlet会利用视图对象对模型数据进行渲染
⑧客户端得到响应,可能是一个一般的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件
157、如何在Spring IoC容器中配置数据源?答DBCP配置bean id=,,dataSourcez/class=,/org.apache mons.dbcp.BasicDataSource,,destroy-method=,,close,,property name二〃driverClassName value=〃${jdbc.driverClassName),z/property name二〃url〃value=〃${jdbc.url}〃/property name=username value=〃${jdbc.username}〃/〉property name=zpassword,/value=〃${jdbc.password}〃/〉/beancontext:property-placeholder location=〃jdbc.properties/〉C3P0配置bean id=dataSource”class=〃com・mchange.v
2.c3p0boPooledDataSource,/destroy-method=close〃〉property name=,,driverClassz,value=〃${jdbc.driverClassName),z/property name二〃jdbcUrl value=〃${jdbc.url}〃/property name=user value=〃${jdbc.username}〃/property name=,,password,/value=〃${jdbc.password}〃//beancontext:property-placeholder location=〃jdbc.properties/〉提示DBCP的具体配置在第153题中已经完整的展示过了
158、如何配置配置事务增加?答xml version=〃l.0〃encoding二〃UTF-8〃?Xbeans xmlns=〃://springframework.xmlns:xsi=,/w
3.org/2023/XMLSchema-instance〃//xmlns:aop=,z springframework.org/schema/aopz,//xmlns:tx二〃springframework,org/schema/tx〃//org/schema/beansz/xsi:schemaLocation=/z://springframework,org/schema/aop/spring-aop.xsd〃!-this isthe serviceobject thatwe wantto maketransactional-bean id=〃fooService class=〃x・y.service.DefaultFooService,z/!--the transactional advice--tx:advice id=〃txAdvice transaction-manager=,,txManager,z!一一the transactionalsemantics...一一tx:attributes!一all methodsstarting withget areread-only-tx:method name=〃get*“read-only二〃true〃/!--other methodsuse thedefault transactionsettings seebelow--tx:method name=〃*〃/〉/tx:attributes/tx:advice!--ensure thatthe abovetransactionaladviceruns forany executionofan operationdefined bythe FooServiceinterface一一aop:config aop:pointcut id=z/fooServiceOperation/zexpression=,,execution*x.y.service.FooService.*・.〃/aop:advisor advice-ref二〃txAdvice pointcut-ref=,,fooServiceOperation,,//aop:config!--don,t forgetthe DataSource一bean id二〃dataSource class=zzorg.apache mons.dbcp.BasicDataSource,zdestroy-method=,/closez,property name=driverClassName〃value二〃oracle,jdbc.driver.OracleDriver/z/property name二value=z,jdbc:oracle:thin:©localhost:1521:orcl〃/property name=username value=,,scott,,/property name=password value=,,tiger,,//bean!一similarly,don,t forgetthe P1atformTransaetionManager一bean id二〃txManager〃class=〃org・springframework,jdbc.datasource.DataSourceTransactionManagerz,properly nanie-^dalaSource,zref-,,dalaSource,,//bean!——other bean/definitions here——
②采纳合理的Session管理机制3尽量运用延迟加载特性4设定合理的批处理参数5假如可以,选用UUID作为主键生成器6假如可以,选用基于版本号的乐观锁替代悲观锁7在开发过程中,开启hibernate.show_sql选项查看生成的SQL,从而了解底层的状况;开发完成后关闭此选项
⑧考虑数据库本身的优化,合理的索引、恰当的数据分区策略等都会对长久层的性能带来可观的提升,但这些须要专业的DBA数据库管理员供应支持
140、谈一谈Hibernate的一级缓存、二级缓存和查询缓存答Hibernate的Session供应了一级缓存的功能,默认总是有效的,当应用程序保存长久化实体、修改长久化实体时,Session并不会马上把这种变更提交到数据库,而是缓存在当前的Session中,除非显示调用了Session的flush方法或通过close方法关闭Session通过一级缓存,可以削减程序及数据库的交互,从而提高数据库访问性能SessionFactory级别的二级缓存是全局性的,全部的Session可以共享这个二级缓存不过二级缓存默认是关闭的,须要显示开启并指定须要运用哪种二级缓存实现类可以运用第三方供应的实现一旦开启了二级缓存并设置了须要运用二级缓存的实体类,SessionFactory就会缓存访问过的该实体类的每个对象,除非缓存的数据超出了指定的缓存空间一级缓存和二级缓存都是对整个实体进行缓存,不会缓存一般属性,假如希望对一般属性进行缓存,可以运用查询缓存查询缓存是将HQL或SQL语句以及它们的查询结果作为键值对进行缓存,对于同样的查询可以干脆从缓存中获得数据查询缓存默认也是关闭的,须要显不开启O
141、Hibernate中DetachedCriteria类是做什么的?答:DetachedCriteria和Criteria的用法基本上是一样的,但Criteria是由Session的createCriteria方法创建的,也就意味着离开创建它的Session,Criteria就无法运用了DetachedCriteria不须要Session就可以创建运用DetachedCriteria.forClass方法创建,所以通常也称其为离线的Criteria,在须要进行查询操作的时候再和Session绑定调用其getExecutableCriteriaSession方法,这也就意味着一个DetachedCriteria可以在须要的时候和不同的Session进行绑定
142、@0neToMany注解的mappedBy属性有什么作用?答@0neToMany用来配置一对多关联映射,但通常状况下,一对多关联映射都由多的一方来维护关联关系,例如学生和班级,应当在学生类中添加班级属性来维持学生和班级的关联关系在数据库中是由学生表中的外键班级编号来维护学生表和班级表的多对一关系,假如要运用双向关联,在班级类中添加一个容器属性来存放学生,并运用@0neToMany注解进行映射,此时mappedBy属性就特别重要假如运用XML进行配置,可以用<set>标签的inverse二〃true〃设置来达到同样的效果/beans
159、选择运用Spring框架的缘由Spring框架为企业级开发带来的好处有哪些?答可以从以下几个方面作答-非侵入式支持基于POJO的编程模式,不强制性的要求实现Spring框架中的接口或继承Spring框架中的类-IoC容器IoC容器帮助应用程序管理对象以及对象之间的依靠关系,对象之间的依靠关系假如发生了变更只须要修改配置文件而不是修改代码,因为代码的修改可能意味着项目的重新构建和完整的回来测试有了IoC容器,程序员再也不须要自己编写工厂、单例,这一点特殊符合Spring的精神〃不要重复的独创轮子〃-A0P面对切面编程将全部的横切关注功能封装到切面aspect中,通过配置的方式将横切关注功能动态添加到目标代码上,进一步实现了业务逻辑和系统服务之间的分别另一方面,有了A0P程序员可以省去很多自己写代理类的工作-MVCSpring的MVC框架是特别优秀的,从各个方面都可以甩Struts2几条街,为Web表示层供应了更好的解决方案-事务管理Spring以宽广的胸怀接纳多种长久层技术,并且为其供应了声明式的事务管理,在不须要任何一行代码的状况下就能够完成事务管理-其他选择Spring框架的缘由还远不止于此,Spring为Java企业级开发供应了一站式选择,你可以在须要的时候运用它的部分和全部,更重要的是,你甚至可以在感觉不到Spring存在的状况下,在你的项目中运用Spring供应的各种优秀的功能
160、Spring IoC容器配置Bean的方式?答-基于XML文件进行配置-基于注解进行配置-基于Java程序进行配置Spring3+package com.jackfrued.bean;import org.springframework,beans,factory,annotation.Autowired;import org.spring framework,stereotype ponent;©Componentpublie classPerson{private Stringname;private int age;@Autowiredprivate Carcar;public PersonStringname,intage{this.name=name;this,age=age;}public voidsetCarCar car{this.car=car;}©Overridepublic StringtoStringO{return Person[name=〃+name+age=〃+age+car=〃+car+}package com.jackfrued.bean;import org.springframework,stereotype ponent;©Componentpublic classCar{private Stringbrand;private int maxSpeed;public CarStringbrand,intmaxSpeed{this.brand=brand;this.maxSpeed=maxSpeed;}©Overridepublic StringtoStringO{return,Car[brand=〃+brand+maxSpeed=〃+maxSpeed+}packagecom.jackfrued.config;import org.springframework,context,annotation.Bean;import.Configuration;import com.jackfrued.bean.Car;import com.jackfrued.bean.Person;©Configurationpublic classAppConfig{@Beanpublic Carcar{return newCar Benz”,320;©Beanpublic Person person{return newPerson〃骆吴〃,34;}packagecom.jackfrued.test;import org;import org;import com;import com;class Test{publicstaticvoidmainString[]args{//TWR Java7+tryConfigurableApplicationContext factory=new AnnotationConfigApplicationContextAppConfig.class{Personperson-factory.gelBeanPerson,class;System,out.printinperson;
161、阐述Spring框架中Bean的生命周期?答
①Spring IoC容器找到关于Bean的定义并实例化该Bean
②Spring IoC容器对Bean进行依靠注入3假如Bean实现了BeanNameAware接口,则将该Bean的id传给setBeanName方法4假如Bean实现了BeanFactoryAware接口,则将BeanFactory对象传给setBeanFactory方法5假如Bean实现了BeanPostProcessor接口,则调用其postProcessBeforelnitialization方法6假如Bean实现了InitializingBean接口,则调用其afterPropertySet方法7假如有和Bean关联的BeanPostProcessors对象,则这些对象的postProcessAfterlnitialization方法被调用8当销毁Bean实例时,假如Bean实现了DisposableBean接口,则调用其destroy方法
162、依靠注入时如何注入集合属性?答:可以在定义Bean属性时,通过〈list〉/set/map/〈props》分别为其注入列表、集合、映射和键值都是字符串的映射属性
163、Spring中的自动装配有哪些限制?答-假如运用了构造器注入或者setter注入,那么将覆盖自动装配的依靠关系-基本数据类型的值、字符串字面量、类字面量无法运用自动装配来注入-优先考虑运用显式的装配来进行更精确的依靠注入而不是运用自动装配
164、在Web项目中如何获得Spring的IoC容器?答WebApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext(servletContext);-
65.大型网站在架构上应当考虑哪些问题?答-分层分层是处理任何困难系统最常见的手段之一,将系统横向切分成若干个层面,每个层面只担当单一的职责,然后通过下层为上层供应的基础设施和服务以及上层对下层的调用来形成一个完整的困难的系统计算机网络的开放系统互联参考模型(OSI/RM)和Internet的TCP/IP模型都是分层结构,大型网站的软件系统也可以运用分层的理念将其分为长久层(供应数据存储和访问服务)、业务层(处理业务逻辑,系统中最核心的部分)和表示层(系统交互、视图展示)须要指出的是
(1)分层是逻辑上的划分,在物理上可以位于同一设备上也可以在不同的设备上部署不同的功能模块,这样可以运用更多的计算资源来应对用户的并发访问;
(2)层及层之间应当有清楚的边界,这样分层才有意义,才更利于软件的开发和维护-分割分割是对软件的纵向切分我们可以将大型网站的不同功能和服务分割开,形成高内聚低耦合的功能模块(单元)在设计初期可以做一个粗粒度的分割,将网站分割为若干个功能模块,后期还可以进一步对每个模块进行细粒度的分割,这样一方面有助于软件的开发和维护,另一方面有助于分布式的部署,供应网站的并发处理实力和功能的扩展-分布式除了上面提到的内容,网站的静态资源(JavaScript.CSS、图片等)也可以采纳独立分布式部署并采纳独立的域名,这样可以减轻应用服务器的负载压力,也使得阅读器对资源的加载更快数据的存取也应当是分布式的,传统的商业级关系型数据库产品基本上都支持分布式部署,而新生的NoSQL产品几乎都是分布式的当然,网站后台的业务处理也要运用分布式技术,例如查询索引的构建、数据分析等,这些业务计算规模浩大,可以运用Hadoop以及MapReduce分布式计算框架来处理-集群集群使得有更多的服务器供应相同的服务,可以更好的供应对并发的支持-缓存所谓缓存就是用空间换取时间的技术,将数据尽可能放在距离计算最近的位置运用缓存是网站优化的第肯定律我们通常说的CDN、反向代理、热点数据都是对缓存技术的运用-异步异步是实现软件实体之间解耦合的又一重要手段异步架构是典型的生产者消费者模式,二者之间没有干脆的调用关系,只要保持数据结构不变,彼此功能实现可以随意变更而不相互影响,这对网站的扩展特别有利运用异步处理还可以提高系统可用性,加快网站的响应速度(用Ajax加载数据就是一种异步技术),同时还可以起到削峰作用(应对瞬时高并发)quot;能推迟处理的都要推迟处理〃是网站优化的其次定律,而异步是践行网站优化其次定律的重要手段-冗余各种服务器都要供应相应的冗余服务器以便在某台或某些服务器宕机时还能保证网站可以正常工作,同时也供应了灾难复原的可能性冗余是网站高可用性的重要保证
166、你用过的网站前端优化的技术有哪些?答
①阅读器访问优化-削减恳求数量合并CSS、合并JavaScript、合并图片(CSS Sprite)-运用阅读器缓存通过设置响应头中的Cache-Control和Expires属性,将CSS、JavaScript,图片等在阅读器中缓存,当这些静态资源须要更新时,可以更新HTML文件中的引用来让阅读器重新恳求新的资源-启用压缩-CSS前置,JavaScript后置-削减Cookie传输
②CDN加速:CDN(Content DistributeNetwork)的本质仍旧是缓存,将数据缓存在离用户最近的地方,CDN通常部署在网络运营商的机房,不仅可以提升响应速度,还可以削减应用服务器的压力当然,CDN缓存的通常都是静态资源
③反向代理反向代理相当于应用服务器的一个门面,可以爱护网站的平安性,也可以实现负载均衡的功能,当然最重要的是它缓存了用户访问的热点资源,可以干脆从反向代理将某些内容返回给用户阅读器
167、你运用过的应用服务器优化技术有哪些?答
①分布式缓存缓存的本质就是内存中的哈希表,假如设计一个优质的哈希函数,那么理论上哈希表读写的渐近时间困难度为0
(1)缓存主要用来存放那些读写比很高、变更很少的数据,这样应用程序读取数据时先到缓存中读取,假如没有或者数据已经失效再去访问数据库或文件系统,并依据拟定的规则将数据写入缓存对网站数据的访问也符合二八定律(Pareto分布,幕律分布),即80%的访问都集中在20%的数据上,假如能够将这20%的数据缓存起来,那么系统的性能将得到显著的改善当然,运用缓存须要解决以下几个问题-频繁修改的数据;-数据不一样及脏读;-缓存雪崩(可以采纳分布式缓存服务器集群加以解决,memcached是广泛采纳的解决方案);-缓存预热;-缓存穿透(恶意持续恳求不存在的数据)
②异步操作可以运用消息队列将调用异步化,通过异步处理将短时间高并发产生的事务消息存储在消息队列中,从而起到削峰作用电商网站在进行促销活动时,可以将用户的订单恳求存入消息队列,这样可以抵挡大量的并发订单恳求对系统和数据库的冲击目前,绝大多数的电商网站即便不进行促销活动,订单系统都采纳了消息队列来处理
③运用集群
④代码优化-多线程基于Java的Web开发基本上都通过多线程的方式响应用户的并发恳求,运用多线程技术在编程上要解决线程平安问题,主要可以考虑以下几个方面A.将对象设计为无状态对象(这和面对对象的编程观点是冲突的,在面对对象的世界中被视为不良设计),这样就不会存在并发访问时对象状态不一样的问题B.在方法内部创建对象,这样对象由进入方法的线程创建,不会出现多个线程访问同一对象的问题运用ThreadLocal将对象及线程绑定也是很好的做法,这一点在前面已经探讨过了C.对资源进行并发访问时应当运用合理的锁机制-非堵塞I/O运用单线程和非堵塞I/O是目前公认的比多线程的方式更能充分发挥服务器性能的应用模式,基于Node,js构建的服务器就采纳了这样的方式Java在JDK
1.4中就引入了N10(Non-blocking I/O),在Servlet3规范中又引入了异步Servlet的概念,这些都为在服务器端采纳非堵塞I/O供应了必要的基础-资源复用资源复用主要有两种方式,一是单例,二是对象池,我们运用的数据库连接池、线程池都是对象池化技术,这是典型的用空间换取时间的策略,另一方面也实现对资源的复用,从而避开了不必要的创建和释放资源所带来的开销
168、什么是XSS攻击?什么是SQL注入攻击?什么是CSRF攻击?答-XSS(Cross SiteScript,跨站脚本攻击)是向网页中注入恶意脚本在用户阅读网页时在用户阅读器中执行恶意脚本的攻击方式跨站脚本攻击分有两种形式反射型攻击(诱运用户点击一个嵌入恶意脚本的链接以达到攻击的目标,目前有很多攻击者利用论坛、微博发布含有恶意脚本的URL就属于这种方式)和长久型攻击(将恶意脚本提交到被攻击网站的数据库中,用户阅读网页时,恶意脚本从数据库中被加载到页面执行,QQ邮箱的早期版本就曾经被利用作为长久型跨站脚本攻击的平台)XSS虽然不是什么簇新玩意,但是攻击的手法却不断翻新,防范XSS主要有两方面消毒(对危急字符进行转义)和Only(防范XSS攻击者窃取Cookie数据)-SQL注入攻击是注入攻击最常见的形式(此外还有OS注入攻击(Struts2的高危漏洞就是通过OGNL实施OS注入攻击导致的)),当服务器运用恳求参数构造SQL语句时,恶意的SQL被嵌入到SQL中交给数据库执行SQL注入攻击须要攻击者对数据库结构有所了解才能进行,攻击者想要获得表结构有多种方式
(1)假如运用开源系统搭建网站,数据库结构也是公开的(目前有很多现成的系统可以干脆搭建论坛,电商网站,虽然便利快捷但是风险是必须要仔细评估的);
(2)错误回显(假如将服务器的错误信息干脆显示在页面上,攻击者可以通过非法参数引发页面错误从而通过错误信息了解数据库结构,Web应用应当设置友好的错误页,一方面符合最小惊异原则,一方面屏蔽掉可能给系统带来危急的错误回显信息);
(3)盲注防范SQL注入攻击也可以采纳消毒的方式,通过正则表达式对恳求参数进行验证,此外,参数绑定也是很好的手段,这样恶意的SQL会被当做SQL的参数而不是吩咐被执行,JDBC中的PreparedStatement就是支持参数绑定的语句对象,从性能和平安性上都明显优于Statemento-CSRF攻击(Cross SiteRequest Forgery,跨站恳求伪造)是攻击者通过跨站恳求,以合法的用户身份进行非法操作(如转账或发帖等)CSRF的原理是利用阅读器的Cookie或服务器的Session,盗取用户身份,其原理如下图所示防范CSRF的主要手段是识别恳求者的身份,主要有以下几种方式
(1)在表单中添加令牌(token);
(2)验证码;
(3)检查恳求头中的Referer(前面提到防图片盗链接也是用的这种方式)令牌和验证都具有一次消费性的特征,因此在原理上一样的,但是验证码是一种糟糕的用户体验,不是必要的状况下不要轻易运用验证码,目前很多网站的做法是假如在短时间内多次提交一个表单未获得胜利后才要求供应验证码,这样会获得较好的用户体验补充防火墙的架设是Web平安的重要保障,ModSecurity是开源的Web防火墙中的佼佼者企业级防火墙的架设应当有两级防火墙,Web服务器和部分应用服务器可以架设在两级防火墙之间的DMZ,而数据和资源服务器应当架设在其次级防火墙之后169,什么是领域模型domain model贫血模型anaemic domainmodel和充血模型rich domainmodel有什么区分?答领域模型是领域内的概念类或现实世界中对象的可视化表示,又称为概念模型或分析对象模型,它专注于分析问题领域本身,发掘重要的业务领域概念,并建立业务领域概念之间的关系贫血模型是指运用的领域对象中只有setter和getter方法POJO,全部的业务逻辑都不包含在领域对象中而是放在业务逻辑层有人将我们这里说的贫血模型进一步划分成失血模型领域对象完全没有业务逻辑和贫血模型领域对象有少量的业务逻辑,我们这里就不对此加以区分了充血模型将大多数业务逻辑和长久化放在领域对象中,业务逻辑业务门面只是完成对业务逻辑的封装、事务和权限等的处理下面两张图分别展示了贫血模型和充血模型的分层架构贫血模型
143、MyBatis中运用#和$书写占位符有什么区分?答#将传入的数据都当成一个字符串,会对传入的数据自动加上引号;$将传入的数据干脆显示生成在SQL中留意运用$占位符可能会导致SQL注射攻击,能用#的地方就不要运用$,写order by子句的时候应当用$而不是
144、说明一下MyBatis中命名空间namespace的作用答:在大型项目中,可能存在大量的SQL语句,这时候为每个SQL语句起一个唯一的标识ID就变得并不简洁了为了解决这个问题,在MyBatis中,可以为每个映射文件起一个唯一的命名空间,这样定义在这个映射文件中的每个SQL语句就成了定义在这个命名空间中的一个IDo只要我们能够保证每个命名空间中这个ID是唯一的,即使在不同映射文件中的语句ID相同,也不会再产生冲突了
145、MyBatis中的动态SQL是什么意思?答对于一些困难的查询,我们可能会指定多个查询条件,但是这些条件可能存在也可能不存在,例如在58同城上面找房子,我们可能会指定面积、楼层和所在位置来查找房源,也可能会指定面积、价格、户型和所在位置来查找房源,此时就须要依据用户指定的条件动态生成SQL语句假如不运用长久层框架我们可能须要自己拼装SQL语句,还好MyBatis供应了动态SQL的功能来解决这个问题MyBatis中用于实现动态SQL的元素主要有-if-choose/when/otherwise-trim-where-set-foreach下面是映射文件的片段select id二〃foo〃parameterType=,/Blog,/resultType二〃Blog〃select*from t_blog where1=1if test=title!=null”〉and title=#{title/ifif test=z,contenl!=and content=#{content}/if iftest=,,owner!=null”〉充血模型贫血模型下组织领域逻辑通常运用事务脚本模式,让每个过程对应用户可能要做的一个动作,每个动作由一个过程来驱动也就是说在设计业务逻辑接口的时候,每个方法对应着用户的一个操作,这种模式有以下几个有点-它是一个大多数开发者都能够理解的简洁过程模型(适合国内的绝大多数开发者)-它能够及一个运用行数据入口或表数据入口的简洁数据访问层很好的协作-事务边界的自不待言,一个事务起先于脚本的起先,终止于脚本的结束,很简洁通过代理(或切面)实现声明式事务然而,事务脚本模式的缺点也是很多的,随着领域逻辑困难性的增加,系统的困难性将快速增加,程序结构将变得极度混乱开源中国社区上有一篇很好的译文《贫血领域模型是如何导致糟糕的软件产生》对这个问题做了比较细致的阐述
170.谈一谈测试驱动开发(TDD)的好处以及你的理解答TDD是指在编写真正的功能实现代码之前先写测试代码,然后依据须要重构实现代码在JUnit的作者Kent Beck的大作《测试驱动开发实战及模式解析》(Test-Driven Development:by Example)一书中有这么一段内容“消退恐惊和不确定性是编写测试驱动代码的重要缘由因为编写代码时的恐惊会让你当心摸索,让你回避沟通,让你羞于得到反馈,让你变得焦躁担心,而TDD是消退恐惊、让Java开发者更加自信更加乐于沟通的重要手段TDD会带来的好处可能不会立刻呈现,但是你在某个时候肯定会发觉,这些好处包括-更清楚的代码一只写须要的代码-更好的设计-更精彩的敏捷性一激励程序员面对接口编程-更快速的反馈一不会到系统上线时才知道bug的存在补充灵敏软件开发的概念已经有很多年了,而且也部分的变更了软件开发这个行业,TDD也是灵敏开发所提倡的TDD可以在多个层级上应用,包括单元测试(测试一个类中的代码)、集成测试(测试类之间的交互)、系统测试(测试运行的系统)和系统集成测试(测试运行的系统包括运用的第三方组件)TDD的实施步骤是红(失败测试)-绿(通过测试)-重构关于实施TDD的具体步骤请参考另一篇文章《测试驱动开发之初窥门径》在运用TDD开发时,常常会遇到须要被测对象须要依靠其他子系统的状况,但是你希望将测试代码跟依靠项隔离,以保证测试代码仅仅针对当前被测对象或方法绽开,这时候你须要的是测试替身测试替身可以分为四类-虚设替身只传递但是不会运用到的对象,一般用于填充方法的参数列表-存根替身总是返回相同的预设响应,其中可能包括一些虚设状态-伪装替身可以取代真实版本的可用版本(比真实版本还是会差很多)-模拟替身可以表示一系列期望值的对象,并且可以供应预设响应Java世界中实现模拟替身的第三方工具特别多,包括EasyMock、Mockito.jMock等and owner二#{owner}/if/select当然也可以像下面这些书写select id=〃foo〃parameterType二〃Blog〃resultType二〃Blog〃select*from tblog where1二1choosewhen test二〃title!=null”〉and title=#{title}/whenwhen test=content!=nuH/zand content=#{content/whenotherwiseand owner=〃owner1〃/otherwise/choose/select再看看下面这个例子select id=bar resultType=//Blogz/select*from tblogwhereid inforeach collection=array〃index二〃index”〃〃〃〃〃〃〃•//./1\\item=item open二separator=,close=/foreach/select
146、什么是loC和DI DI是如何实现的?答loC叫限制反转,是Inversion ofControl的缩写,DI(Dependency Injection)叫依靠注入,是对loC更简洁的诠释限制反转是把传统上由程序代码干脆操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理所谓的〃限制反转〃就是对组件对象限制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依靠关系loC体现了好莱坞原则-〃Don tcall me,we willcall you依靠注入的基本原则是应用组件不应当负责查找资源或者其他依靠的协作对象配置对象的工作应当由容器负责,查找资源的逻辑应当从应用组件的代码中抽取出来,交给容器来完成DI是对loC更精确的描述,即组件之间的依靠关系由容器在运行期确定,形象的来说,即由容器动态的将某种依靠关系注入到组件之中举个例子一个类A须要用到接口B中的方法,那么就须要为类A和接口B建立关联或依靠关系,最原始的方法是在类A中创建一个接口B的实现类C的实例,但这种方法须要开发人员自行维护二者的依靠关系,也就是说当依靠关系发生变动的时候须要修改代码并重新构建整个系统假如通过一个容器来管理这些对象以及对象的依靠关系,则只须要在类A中定义好用于关联接口B的方法(构造器或setter方法),将类A和接口B的实现类C放入容器中,通过对容器的配置来实现二者的关联依靠注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常运用构造器注入来注入必需的依靠关系,对于可选的依靠关系,则setter注入是更好的选择,setter注入须要类供应无参构造器或者无参的静态工厂方法来创建对象
147、Spring中Bean的作用域有哪些?答在Spring的早期版本中,仅有两个作用域singleton和prototype,前者表示Bean以单例的方式存在;后者表示每次从容器中调用Bean时,都会返回一个新的实例,prototype通常翻译为原型补充设计模式中的创建型模式中也有一个原型模式,原型模式也是一个常用的模式,例如做一个室内设计软件,全部的素材都在工具箱中,而每次从工具箱中取出的都是素材对象的一个原型,可以通过对象克隆来实现原型模式。
个人认证
优秀文档
获得点赞 0