目录
9.Spring的声明式事务能不能为普通的类产生代理接口,能不能在代码中使用Try/Catch能捕获异常,如果不可以,请说明原因
10.可以在Spring中注入一个null 和一个空字符串吗?
5.Spring怎么配置事务(具体说出一些关键的xml元素).
6.你对Spring的理解,非单例注入的原理?它的生命周期?
循环注入的原理, aop的实现原理,说说aop中的几个术语,
7.Springmvc 中DispatcherServlet初始化过程及SpringMVC运行原理
10.Spring的Controller是单例还是多例,怎么保证并发的安全
12.spring mvc 和 struts 的区别是什么?
17.mybatis 是否支持延迟加载?延迟加载的原理是什么?
19.mybatis 和 hibernate 的区别有哪些?
40.spring boot 配置文件有哪几种类型?它们有什么区别?
48.hibernate 中如何在控制台查看打印的 sql 语句?
50.hibernate 实体类可以被定义为 final 吗?
51.在 hibernate 中使用 Integer 和 int 做映射有什么区别?
56.在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
57.hibernate 实体类必须要有无参构造函数吗?为什么?
@Resource,@Autowired,@Inject 这3种都是用来注入bean的,它们属于不同的程序中。
1.Spring框架中的三大核心思想是什么
- DI(依赖注入)
- IOC(控制反转)
- AOP(面向切面编程)
2.Spring框架包有哪些,分别的作用是什么?
- Spring-context,上下文,用于缓存、注解、远程调用等
- Spring-aop,用于配置面向切换编程,如配置事务的切面、日志切面
- Spring-tx,用于配置事务
- Spring-web,用于配置在web.xml加载applicationContext配置文件
- Spring-mvc,拦截请求,配置控制器
3.Spring的配置文件有哪些内容?
- 配置注解扫描
- 配置数据源
- 配置连接池
- 配置会话工厂
- 配置AOP
4.说下Spring中常用的注解有哪些?
- @Controller
- @Service
- @repository
- @ResponseBody
- @RequestBody
- @RequestMapping
- @Transaction
- @Autowired
5.怎么样理解IOC和DI
IOC:Inversion of Control,控制反转模式(也称作依赖性介入)的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接创建对象,由容器 (在 Spring 框架中是 IOC 容器) 负责创建对象,程序员只需要声明如何创建对象即可。
DI:依赖注入,类中声明属性和set方法,Spring会通过set方法,注入属性的值
6.AOP的概念以及使用AOP机制有什么好处
AOP的概念是Aspected Oriented Programming 面向切面编程
AOP将程序分解成各个切面或者说关注点。这使得可以模块化,相当横向上分切了。
它可以解决OOP和过程化方法不能够很好解决的横切(crosscut)问题,
如:事务、安全、日志等横切关注。
7.Java编程中实现AOP有几种方式?
1.使用xml配置文件配置
2.使用@Aspect注解配置
@Component
@Aspect
public class LoggingAspect {
/**
* 前置通知:目标方法执行之前执行以下方法体的内容
*/
@Before("execution(* com.gyf.beans.aop.*.*(..))")
public void beforeMethod(JoinPoint jp){
}
/**
* 后置通知
*/
@AfterReturning(value="execution(* com.gyf.beans.aop.*.*(..))",returning="result")
public void afterReturningMethod(JoinPoint jp, Object result){
}
}
8.Spring框架中的事务处理有几种,阐述两者的区别
spring提供的事务管理可以分为两类:编程式的和声明式的。
编程式的,比较灵活,但是代码量大,存在重复的代码比较多;
声明式的比编程式的更灵活.
9.Spring的声明式事务能不能为普通的类产生代理接口,能不能在代码中使用Try/Catch能捕获异常,如果不可以,请说明原因
不能。
Spring的声明式事务为实现类产生代理。
不能在代码中使用Try/Catch,因为代码中捕获了异常,Spring容器捕获不了异常。
10.可以在Spring中注入一个null 和一个空字符串吗?
可以
11.介绍Spring框架的优点?
- Spring是分层的架构,你可以选择使用你需要的层而不用管不需要的部分
- Spring是POJO编程,POJO编程使得可持续构建和可测试能力提高
- 依赖注入和IOC使得JDBC操作简单化
- Spring是开源的免费的
- Spring使得对象管理集中化,简单化
1.讲讲Spring加载流程。
- 首先解析 spring.xml 配置文件,把其中 <bean> 解析为 BeanDefinition, 存入beanFactory
<bean id="" class="" init-method="" destroy-method="" scope="" lazy-init="">
- 把 BeanDefinition 中的定义读取到一个map集合中管理起来了,但还没有创建 bean 的单例对象
- 执行beanFactory的后处理器
- 接下来 由 beanFactory 创建每个类对应的单例对象, 利用了反射根据类名创建每个类的实例对象(构造,初始化方法)
- 执行 bean 的后处理器, 它其中有两个方法,会在 bean 的初始化方法前后被调用
- 会把这些结果 存入 beanFactory 的 singletonObjects 这样一个map集合里
userService -> userService对象
- 执行依赖注入主要为了解决循环引用问题
2. Spring AOP的实现原理
AOP(面向方面编程):是OOP的补充和完善。
OOP引入了封装、继承、多态性等建立一种对象层次结构(从上到下的关系)。
当需要为分散的对象引入公共行为的时候(从左到右的关系),OOP就显得无能为力。
例如:日志功能。日志代码往往水平的散步所有对象层次中,与对象的核心功能毫无关系。
这种代码被称为横切(cross-cutting)代码还有像安全性、异常处理、透明的持续性等都称为横切代码。在OOP设计中,它们导致了大量代码的重复,不利于模块的重用。
- AOP与OOP相反,利用“横切”技术将影响多个类的公共行为封装到一个可重用模块,称为Aspect。
- 简单点,就是将那些与业务无关,却被业务模块所共同调用的逻辑封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”
- Spring提供了两种方式生成代理对象:JDKProxy和Cglib具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。
下面我们来研究一下Spring如何使用JDK来生成代理对象,具体的生成代码放在JdkDynamicAopProxy这个类中:
3.讲讲Spring事务的传播属性。
- —— 支持当前事务,如果当前没有事务,就新建一个事务。(常见的选择)比如ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED,那么由于执行ServiceA.methodA的时候,ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没有在事务中,他就会为自己分配一个事务。这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。即使ServiceB.methodB的事务已经被提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚。
- PROPAGATION_SUPPORTS —— 支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY ——支持当前事务,如果当前没有事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW ——支持当前事务,如果当前没有事务,就将当前事务挂起。如ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,A才继续执行。他与PROPAGATION_REQUIRED的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。
- PROPAGATION_NOT_SUPPORTED —— 以非事务方式执行当前操作,如果当前存在事务,就把事务挂起来。
- PROPAGATION_NEVER —— 以非事务方式执行,如果当前存在事务,则抛异常。
- PROPAGATION_NESTED—— 如果当前存在事务,则在嵌套事务内执行,关键是savepoint。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。与PROPAGATION_REQUIRES_NEW的区别是NESTED的事务和他的父事务是相依的,它的提交是要等父事务一块提交。也就是说,如果父事务最后回滚,它也要回滚。
4.Spring如何管理事务的。
Spring事务管理主要包括3个接口,Spring事务主要由以下三个共同完成的:
PlatformTransactionManager:事务管理器,主要用于平台相关事务的管理。
主要包括三个方法:
① commit:事务提交。
② rollback:事务回滚。
③ getTransaction:获取事务状态。
TransacitonDefinition:事务定义信息,用来定义事务相关属性,给事务管理器PlatformTransactionManager使用这个接口有下面四个主要方法:
① getIsolationLevel:获取隔离级别。
② getPropagationBehavior:获取传播行为。
③ getTimeout获取超时时间。
④ isReadOnly:是否只读(保存、更新、删除时属性变为false--可读写,查询时为true--只读)事务管理器能够根据这个返回值进行优化,这些事务的配置信息,都可以通过配置文件进行配置。
TransationStatus:事务具体运行状态,事务管理过程中,每个时间点事务的状态信息。
例如:
① hasSavepoint():返回这个事务内部是否包含一个保存点。
② isCompleted():返回该事务是否已完成,也就是说,是否已经提交或回滚。
③ isNewTransaction():判断当前事务是否是一个新事务。
5.Spring怎么配置事务(具体说出一些关键的xml元素).
- ☞ 配置事务的方法有两种:
- 1)基于XML的事务配置。
- 2)基于注解方式的事务配置。
铺垫:
- 1)spring的事务管理是通过Aop的方式来实现。
- 2)声明式事务是spring对事务管理的最常用的方式,因为这种方式对代码的影响最小,因此也就符合非侵入式的轻量级的容器的概念;
基于XML的事务配置:
<?xml version="1.0" encoding="UTF-8"?> <!-- from the file 'context.xml' --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- 数据元信息 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <!-- 管理事务的类,指定我们用谁来管理我们的事务--> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 首先我们要把服务对象声明成一个bean 例如HelloService --> <bean id="helloService" class="com.yintong.service.HelloService"/> <!-- 然后是声明一个事物建议tx:advice,spring为我们提供了事物的封装,这个就是封装在了<tx:advice/>中 --> <!-- <tx:advice/>有一个transaction-manager属性,我们可以用它来指定我们的事物由谁来管理。 默认:事务传播设置是 REQUIRED,隔离级别是DEFAULT --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!-- 配置这个事务建议的属性 --> <tx:attributes> <!-- 指定所有get开头的方法执行在只读事务上下文中 --> <tx:method name="get*" read-only="true"/> <!-- 其余方法执行在默认的读写上下文中 --> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 我们定义一个切面,它匹配FooService接口定义的所有操作 --> <aop:config> <!-- <aop:pointcut/>元素定义AspectJ的切面表示法,这里是表示com.yintong.service.helloService包下的任意方法。 --> <aop:pointcut id="helloServiceOperation" expression="execution(* com.yintong.service.helloService.*(..))"/> <!-- 然后我们用一个通知器:<aop:advisor/>把这个切面和tx:advice绑定在一起,表示当这个切面:fooServiceOperation执行时tx:advice定义的通知逻辑将被执行 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="helloServiceOperation"/> </aop:config> </beans>
- 基于注解方式的事务配置 : @Transactional:直接在Java源代码中声明事务的做法让事务声明和将受其影响的代码距离更近了,而且一般来说不会有不恰当的耦合的风险,因为,使用事务性的代码几乎总是被部署在事务环境中。
- ♣ 注解事务,只需要在XML配置中配置一句就可以了,如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <bean id="helloService" class="com.yintong.service.HelloService"/> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置注解事务 --> <tx:annotation-driven transaction-manager="txManager"/> </beans>
- ♣ 主要在类中定义事务注解@Transactional,如下:
//@Transactional 注解可以声明在类上,也可以声明在方法上。在大多数情况下,方法上的事务会首先执行 @Transactional(readOnly = true) public class HelloService{ public Foo getFoo(String fooName) { } //@Transactional 注解的事务设置将优先于类级别注解的事务设置 propagation:可选的传播性设置 @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) public void updateFoo(Hel hel) { } }
6.你对Spring的理解,非单例注入的原理?它的生命周期?
循环注入的原理, aop的实现原理,说说aop中的几个术语,
它们是怎么相互工作的。
✔ Spring的理解:
- Spring是一个开源框架,主要是为简化企业级应用开发而生。
- Spring是一个IOC和AOP容器框架。
- ♧ 控制反转(IOC):Spring容器使用了工厂模式为我们创建了所需要的对象,我们使用时不需要自己去创建,直接调用Spring为我们提供的对象即可,这就是控制反转的思想。
- ♧ 依赖注入(DI):Spring使用Java Bean对象的Set方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程就是依赖注入的基本思想。
- ♧ 面向切面编程(AOP):在面向对象编程(OOP)思想中,我们将事物纵向抽象成一个个的对象。而在面向切面编程中,我们将一个个对象某些类似的方面横向抽象成一个切面,对这个切面进行一些如权限验证,事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。
- 在Spring中,所有管理的都是JavaBean对象,而BeanFactory和ApplicationContext就是Spring框架的那个IOC容器,现在一般使用ApplicationContext,其不但包括了BeanFactory的作用,同时还进行了更多的扩展。
- ✔ 非单例注入原理:在大部分情况下,容器中的bean都是singleton类型的。如果一个singleton bean要引用另外一个singleton bean或者一个非singleton bean要引用另外一个非singleton,通常情况下将一个bean定义为另一个bean的property值就可以了。不过对于具有不同生命周期的bean来说这样做就会有问题了,比如在调用一个singleton类型bean A的某个方法时,需要引用另一个非singleton(prototype)类型的bean B,对于bean A来说,容器只会创建一次,这样就没法在需要的时候每次让容器为bean A提供一个新的的bean B实例。
注入原理: https://www.cnblogs.com/mthoutai/p/7278427.html
生命周期:https://blog.youkuaiyun.com/a327369238/article/details/52193822
循环注入原理:https://blog.youkuaiyun.com/jijianshuai/article/details/78122738
7.Springmvc 中DispatcherServlet初始化过程及SpringMVC运行原理
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用处理器映射器HandlerMapping。
- 处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
- DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
- 执行处理器Handler(Controller,也叫页面控制器)。
- Handler执行完成返回ModelAndView
- HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover解析后返回具体View
- DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
- DispatcherServlet响应用户。
组件说明:
1.DispatcherServlet:前端控制器。
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性,系统扩展性提高。由框架实现
2.HandlerMapping:处理器映射器。
HandlerMapping负责根据用户请求的url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,根据一定的规则去查找,例如:xml配置方式,实现接口方式,注解方式等。由框架实现
3.Handler:处理器。
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。
4.HandlAdapter:处理器适配器。
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。由框架实现。
5.ModelAndView是springmvc的封装对象,将model和view封装在一起。
6.ViewResolver:视图解析器
ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
7.View:
是springmvc的封装对象,是一个接口, springmvc框架提供了很多的View视图类型,包括:jspview,pdfview,jstlView、freemarkerView、pdfView等。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
详情:
8.Springmvc用到的注解,作用是什么,原理
- 上在面的 DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter 是 Spring 为 @Controller 分发请求所必需的。
- annotation-driven 扫描指定包中类上的注解,常用的注解有:
- @Controller 声明Action组件
- @Service 声明Service组件 @Service("myMovieLister")
- @Repository 声明Dao组件
- @Component 泛指组件, 当不好归类时.
- @RequestMapping("/menu") 请求映射
- @Resource 用于注入,( j2ee提供的 ) 默认按名称装配,@Resource(name="beanName")
- @Autowired 用于注入,(srping提供的) 默认按类型装配
- @Transactional( rollbackFor={Exception.class}) 事务管理
- @ResponseBody
- @Scope("prototype") 设定bean的作用域
9.Springboot启动机制。
@Target(ElementType.TYPE) // 注解的适用范围,其中TYPE用于描述类、接口(包括包注解类型)或enum声明
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期,保留到class文件中(三个生命周期)
@Documented // 表明这个注解应该被javadoc记录
@Inherited // 子类可以继承该注解
@SpringBootConfiguration // 继承了Configuration,表示当前是注解类
@EnableAutoConfiguration // 开启springboot的注解功能,springboot的四大神器之一,其借助@import的帮助
@ComponentScan(excludeFilters = { // 扫描路径设置(具体使用待确认)
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
https://www.cnblogs.com/shamo89/p/8184960.html
10.Spring的Controller是单例还是多例,怎么保证并发的安全
singleton:单例模式,当spring创建applicationContext容器的时候,spring会欲初始化所有的该作用域实例,加上lazy-init就可以避免预处理;
prototype原型模式,每次通过getBean获取该bean就会新产生一个实例,创建后spring将不再对其管理;
为什么spring要默认是单例呢?
- 为了性能。
- 不需要多例。
最佳实践:
- 不要在controller中定义成员变量。
- 万一必须要定义一个非静态成员变量时候,则通过注解@Scope("prototype"),将其设置为多例模式
11. Mybatis的底层实现原理
mybatis底层还是采用原生jdbc来对数据库进行操作的,只是通过 SqlSessionFactory,SqlSession Executor,StatementHandler,ParameterHandler,ResultHandler和TypeHandler等几个处理器封装了这些过程
执行器:Executor
(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
参数处理器: ParameterHandler (getParameterObject, setParameters)
结构处理器 ResultSetHandler (handleResultSets, handleOutputParameters)
sql查询处理器:StatementHandler (prepare, parameterize, batch, update, query)
其中StatementHandler用通过ParameterHandler与ResultHandler分别进行参数预编译 与结果处理。
而ParameterHandler与ResultHandler都使用TypeHandler进行映射。如下图:
2.Mybatis工作过程
通过读mybatis的源码进行分析mybatis的执行操作的整个过程,我们通过debug调试就可以知道Mybatis每一步做了什么事,我先把debug每一步结果 截图,然后在分析这个流程。
第一步:读取配置文件,形成InputStream
https://blog.youkuaiyun.com/u014297148/article/details/78696096
12.spring mvc 和 struts 的区别是什么?
- 拦截级别: struts2是类级别的拦截; springmvc是方法级别的拦截。
- 数据独立性: spring mvc的方法之间基本上独立的,独享request和response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量;而struts2虽然方法之间也是独立的,但其所有action变量是共享的,这不会影响程序运行,却给我们编码和读程序时带来了一定的麻烦。
- 拦截机制: struts2有以自己的interceptor机制, spring mvc用的是独立的aop方式,这样导致struts2的配置文件量比spring mvc大。
- 对ajax的支持: spring mvc集成了ajax,所有ajax使用很方便,只需要一个注解@ResponseBody就可以实现了;而struts2一般需要安装插件或者自己写代码才行。
13.mybatis 中 #{}和 ${}的区别是什么?
- #{ }是预编译处理
- ${ }是字符替换
- 在使用#{ }时, MyBatis会将SQL中的#{ }替换成"?",进行预编译
- 再配合PreparedStatement的set方法赋值
- 这样可以有效的防止SQL注入,保证程序的运行安全。
- ${ } 是直接把字符串带入
14.mybatis 有几种分页方式?
分页方式:逻辑分页和物理分页。
逻辑分页:使用MyBatis自带的RowBounds进行分页,它是一次性查询很多数据,然后在数据中再进行检索。
物理分页: 自己手写SQL分页或使用分页插件PageHelper,去数据库查询指定条数的分页数据的形式。
15.RowBounds 是一次性查询全部结果吗?为什么?
RowBounds表面是在“所有”数据中检索数据,其实并非是一次性查询出所有数据,因为MyBatis是对jdbc的封装,在jdbc驱动中有一个Fetch Size的配置,它规定了每次最多从数据库查询多少条数据,假如你要查询更多数据,它会在你执行next()的时候,去查询更多的数据。
就好比你去自动取款机取10000元,但取款机每次最多能取2500元,所以你要取4次才能把钱取完。只是对于jdbc来说,当你调用next()的时候会自动帮你完成查询工作。
这样做的好处可以有效的防止内存溢出。
16.mybatis 逻辑分页和物理分页的区别是什么?
逻辑分页是一次性查询很多数据,然后再在结果中检索分页的数据。
这样做弊端是需要消耗大量的内存、有内存溢出的风险、对数据库压力较大。
物理分页是从数据库查询指定条数的数据,弥补了一次性全部查出的所有数据的种种缺点,比如需要大量的内存,对数据库查询压力较大等问题。
17.mybatis 是否支持延迟加载?延迟加载的原理是什么?
MyBatis支持延迟加载,设置lazyLoadingEnabled-true即可。
延迟加载的原理的是调用的时候触发加载,而不是在初始化的时候就加载信息。
比如语用 a. getB().getName(),这个时候发现a. getB()的值为null,此时会单独触发事先保存好的关联B对象的SQL,先查询出来B,然后再调用a. setB(b),而这时候再调用a. getB().getName()就有值了,这就是延迟加载的基本原理。
18.说一下 mybatis 的一级缓存和二级缓存?
- 一级缓存:基于PerpetualCache的HashMap本地缓存,它的声明周期是和SQLSession一致的,有多个SQLSession或者分布式的环境中数据库操作,可能会出现脏数据。当Session flush或close之后,该Session中的所有Cache就将清空。
- 默认一级缓存是开启的。
- 二级缓存:也是基于PerpetualCache的HashMap本地缓存,不同在于其存储作用域为Mapper级别的,如果多个SQLSession之间需要共享缓存,则需要使用到二级缓存,并且二级缓存可自定义存储源,如Ehcache。
- 默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态)。
- 开启二级缓存数据查询流程:二级缓存-->一级缓存-->数据库
- 缓存更新机制:当某一个作用域(一级缓存Session/二级缓存Mapper)进行了C/U/D操作后,默认该作用域下所有select中的缓存将被clear。
19.mybatis 和 hibernate 的区别有哪些?
- 灵活性:MyBatis更加灵活,自己可以写SQL语句,使用起来比较方便。
- 可移植性:MyBatis有很多自己写的SQL,因为每个数据库的SQL可以不相同,所以可移植性比较差
- 学习和使用门槛:MyBatis入门比较简单,使用门槛也更低。
- 二级缓存:hibernate拥有更好的二级缓存,它的二级缓存可以自行更换为第三方的二级缓存。
20.mybatis 有哪些执行器(Executor)?
MyBatis有三种基本的Executor执行器:
- SimpleExecutor:每执行一次update或select就开启一个Statement对象,用完立刻关闭Statement对象。
- ReuseExecutor:执行update或select,以SQL作为key查找Statement对象,存在就使用,不存在就创建,用完后不关闭Statement对象,而是放置于Map内供下一次使用。简言之,就是重复使用Statement对象
- BatchExecutor:执行update (没有select, jdbc批处理不支持select) ,将所有SQL都添加到批处理中(addBatch() ),等待统一执行(executeBatch()) ,它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理,与jdbc批处理相同。
21.mybatis 分页插件的实现原理是什么?
分页插件的基本原理是使用MyBatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的SQL,然后重写SQL,根据dialect方言,添加对应的物理分页语句和物理分页参数。
22.mybatis 如何编写一个自定义插件?
23.为什么要使用 spring?
1.简介
-
目的:解决企业应用开发的复杂性
-
功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
-
范围:任何Java应用
简单来说,Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。
2.轻量
从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。
3.控制反转
Spring通过一种称作控制反转(IOC)的技术促进了松耦合。当应用了IOC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IOC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
4.面向切面
Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
5.容器
Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
6.框架
Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。
24.解释一下什么是 AOP?
AOP(面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。
使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。
业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。
Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”
25.解释一下什么是IOC
IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”。
简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。
IOC理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦。如下图:
图 IOC解耦过程
大家看到了吧,由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来。
我们再来做个试验:把上图中间的IOC容器拿掉,然后再来看看这套系统:
图 拿掉IOC容器后的系统
我们现在看到的画面,就是我们要实现整个系统所需要完成的全部内容。这时候,A、B、C、D这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。所以,如果真能实现IOC容器,对于系统开发而言,这将是一件多么美好的事情,参与开发的每一成员只要实现自己的类就可以了,跟别人没有任何关系!
我们再来看看,控制反转(IOC)到底为什么要起这么个名字?我们来对比一下:
软件系统在没有引入IOC容器之前,如图1所示,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。
软件系统在引入IOC容器之后,这种情形就完全改变了,如图3所示,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。
通过前后的对比,我们不难看出来:对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。
26.Spring 有哪些主要模块?
Spring框架至今已集成了20多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。
27.spring 常用的注入方式有哪些?
Spring通过DI(依赖注入)实现IOC(控制反转),常用的注入方式主要有三种:
-
构造方法注入
-
setter注入
-
基于注解的注入
28.Spring 中的 bean 是线程安全的吗?
Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究。
Spring容器中的bean默认是单例模式
29.spring 支持几种 bean 的作用域?
当通过spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。
Spring支持如下5种作用域:
-
singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
-
prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例
-
request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
-
session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
-
globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效
其中比较常用的是singleton和prototype两种作用域。
对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。
如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。
而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。
30.Spring 自动装配 bean 有哪些方式?
Spring容器负责创建应用程序中的bean同时通过ID来协调这些对象之间的关系。作为开发人员,我们需要告诉Spring要创建哪些bean并且如何将其装配到一起。
Spring中bean装配有两种方式:
-
隐式的bean发现机制和自动装配
-
在java代码或者XML中进行显示配置
当然这些方式也可以配合使用。
31.Spring 事务实现方式有哪些?
-
编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
-
基于TransactionProxyFactoryBean 的声明式事务管理
-
基于@Transactional 的声明式事务管理
-
基于@Aspect AOP 配置事务
32.说一下 spring 的事务隔离?
事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题:
-
脏读:一个事务读到另一个事务未提交的更新数据。
-
幻读:例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样。
-
不可重复读:比方说在同一个事务中先后执行两条一模一样的select语句,期间在此次事务中没有执行过任何DDL语句,但先后得到的结果不一致,这就是不可重复读。
33.说一下 spring mvc 运行流程?
Spring运行流程描述:
1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter;(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
-
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
-
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
-
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
-
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7. ViewResolver 结合Model和View,来渲染视图;
8. 将渲染结果返回给客户端。
34.spring mvc 有哪些组件?
Spring MVC的核心组件:
-
DispatcherServlet:中央控制器,把请求给转发到具体的控制类
-
Controller:具体处理请求的控制器
-
HandlerMapping:映射处理器,负责映射中央处理器转发给controller时的映射策略
-
ModelAndView:服务层返回的数据和视图层的封装类
-
ViewResolver:视图解析器,解析具体的视图
-
Interceptors :拦截器,负责拦截我们定义的请求然后做处理工作
35.@RequestMapping 的作用是什么?
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性,下面我们把她分成三类进行说明。
-
value:指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);
-
method:指定请求的method类型, GET、POST、PUT、DELETE等;
-
consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
-
produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
-
params: 指定request中必须包含某些参数值是,才让该方法处理。
-
headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。
36.@Autowired 的作用是什么?
这个注解就是spring可以自动帮你把bean里面引用的对象的setter/getter方法省略,它会自动帮你set/get。
1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:
@Autowired()@Qualifier("baseDao")
privateBaseDao baseDao;
3、@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@Resource(name="baseDao")
privateBaseDao baseDao;
推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。
blog.youkuaiyun.com/u013257679/article/details/52295106
37.什么是 Spring boot?
Spring Boot使用“习惯优于配置”的理念,简单来说,它提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题。使用Spring Boot可以不用或者只需要很少的Spring配置就可以让企业项目快速运行起来。
Spring Boot的核心功能
1、 可独立运行的Spring项目:Spring Boot可以以jar包的形式独立运行。
2、 内嵌的Servlet容器:Spring Boot可以选择内嵌Tomcat、Jetty或者Undertow,无须以war包形式部署项目。
3、 简化的Maven配置:Spring提供推荐的基础 POM 文件来简化Maven 配置。
4、 自动配置Spring:Spring Boot会根据项目依赖来自动配置Spring 框架,极大地减少项目要使用的配置。
5、 提供生产就绪型功能:提供可以直接在生产环境中使用的功能,如性能指标、应用信息和应用健康检查。
6、 无代码生成和xml配置:Spring Boot不生成代码。完全不需要任何xml配置即可实现Spring的所有配置。
Springboot是为Spring服务的,是用来简化新Spring应用的初始搭建以及开发过程的。
38.为什么要用 spring boot?
- 配置简单
- 独立运行
- 自动装配
- 无代码生成和xml配置
- 提供应用监控
- 易上手
- 提升开发效率
39.spring boot 核心配置文件是什么?
spring boot核心的两个配置文件:
- bootstrap (.yml 或者. properties):boostrap由父ApplicationContext加载的,比applicaton优先加载,boostrap里面的属性不能被覆盖;
- application (.yml或者. properties):用于spring boot项目的自动化配置。
40.spring boot 配置文件有哪几种类型?它们有什么区别?
配置文件有.properties格式和.yml 格式 ,它们主要的区别是书法风格不同。
- properties 配置如下:
spring. RabbitMQ. port=5672
- yml配置如下:
spring:
RabbitMQ
port: 5672
- yml格式不支持@PropertySource注解导入。
41.spring boot 有哪些方式可以实现热部署?
- 使用devtools启动热部署,添加devtools库,在配置文件中把spring. devtools.restart. enabled设置为true;
- 使用Intelli dea编辑器,勾上自动编译或手动重新编译。
42.jpa 和 hibernate 有什么区别?
- jpa全称Java Persistence APl,是Java持久化接口规范, hibernate属于jpa的具体实现。
43.什么是 spring cloud?
Spring cloud是一系列框架的有序集合。它利用Spring boot的开发便利性巧妙地简化了分布式系统基础设施的开发
如服务发现注册、配置中心、消息总线、负载均衡、断路器hystrix、数据监控等,都可以用spring boot的开发风格做到一键启动和部署。
44.Spring cloud 断路器的作用是什么?
hystrix 在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝) ,向调用方返回一个错误响应,而不是长时间的等待。
这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
45.spring cloud 的核心组件有哪些?
- Eureka:服务注册于发现。
Eureka Client:负责将这个服务的信息注册到 Eureka Server 中。
Eureka Server:注册中心,里面有一个注册表,保存了各个服务所在的机器和端口号。
- Feign:基于动态代理机制,根据注解和选择的机器,拼接请求url地址,发起请求。
- Ribbon:实现负载均衡,从一个服务的多台机器中选择一台。
- Hystrix: 熔断器Hystrix是容错管理工具,作用是通过隔离、控制服务从而对延迟和故障提供更强大的容错能力,避免整个系统被拖垮
- Zuul:网关管理,由Zul网关转发请求给对应的服务。
断路器可以防止一个应用程序多次试图执行一个操作,即很可能失败,允许它继续而不等待故障恢复或者浪费 CPU 周期,而它确定该故障是持久的。断路器模式也使应用程序能够检测故障是否已经解决。如果问题似乎已经得到纠正,应用程序可以尝试调用操作
Ribbon和Feign以及Eureka紧密协作,完成工作的,具体如下:
- 首先Ribbon会从Eureka Client里获取到对应的服务注册表,也就知道了所有的服务都部署在哪些机器上,在监听哪些端口号;
- 然后Ribbon就可以使用默认的Round Robin算法,从中选择一台机器;
- Feign就会针对这台机器,构造并发起请求
46.为什么要使用 hibernate?
- hibernate是对jdbc的封装,大大简化了数据访问层的繁琐的重复性代码。
- hibernate是一个优秀的ORM实现,很多程度上简化了DAO层的编码功能。
- 可以很方便的进行数据库的移植工作。
- 提供了缓存机制,是程序执行更改的高效。
47.什么是 ORM 框架?
ORM (Object Relation Mapping)对象关系映射,是把数据库中的关系数据映射成为程序中的对象。
使用ORM的优点:提高了开发效率降低了开发成本、开发更简单更对象化、可移植更强。
48.hibernate 中如何在控制台查看打印的 sql 语句?
在Config里面把hibernate. show_SQL设置为true就可以。但不建议开启,开启之后会降低程序的运行效率。
49.hibernate 有几种查询方式?
三种: HQL、原生SQL、条件查询Criteria。
50.hibernate 实体类可以被定义为 final 吗?
实体类可以定义为final类,但这样的话就不能使用hibernate代理模式下的延迟关联提
供性能了,所以不建议定义实体类为final。
51.在 hibernate 中使用 Integer 和 int 做映射有什么区别?
Integer类型为对象,它的值允许为null,而int属于基础数据类型,值不能为null。
52.hibernate 是如何工作的?
- 读取并解析配置文件。
- 读取并解析映射文件,创建SessionFactory。
- 打开Session。
- 创建事务。
- 进行持久化操作。
- 提交事务。
- 关闭Session。
- 关闭SessionFactory。
53.get()和 load()的区别?
- 数据查询时,没有OID指定的对象,get()返回null; load()返回一个代理对象。
- load()支持延迟加载;get()不支持延迟加载。
54.说一下 hibernate 的缓存机制?
- hibernate常用的缓存有一级缓存和二级缓存:
- 一级缓存:也叫Session缓存,只在Session作用范围内有效,不需要用户干涉,由nibernate自身维护,可以通过: evict(object) 清除object的缓存; clear()清除一级缓存中的所有缓存;flush()刷出缓存;
- 二级缓存:应用级别的缓存,在所有Session中都有效,支持配置第三方的缓存。如:EhCache.
55.hibernate 对象有哪些状态?
- 临时/瞬时状态:直接new出来的对象,该对象还没被持久化(没保存在数据库中),不受Session管理。
- 持久化状态:当调用Session的save / saveorupdate / get/ load / list等方法的时候,对象就是持久化状态。
- 游离状态:Session关闭之后对象就是游离状态。
56.在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
- getCurrentSession会绑定当前线程,而openSession则不会。
- getCurrentSession事务是Spring控制的,并且不需要手动关闭,而openSession需要我们自己手动开启和提交事务。
57.hibernate 实体类必须要有无参构造函数吗?为什么?
- hibernate中每个实体类必须提供一个无参构造函数,因为hibernate框架要使用reflection api,通过调用Class newinstancel()来创建实体类的实例,如果没有无参的构造 函数就会抛出异常。
58.Spring 的 DI 是什么
不管是面向对象,还是面向过程,都需要分成许多的块,然后由这些部件协同工作完成任务要协同工作就会产生依赖,一个方法调用另一个方法,一个对象包含另一个对象
如果对象 A 包含对象 B 的话,就需要在 A 里 new 一个 B
依赖注入从具体类 B 里抽象出接口 IB——IB 的具体实现可能有很多 B,B1,B2...很多种——这样 A 可以不用再 new 具体的 B 了,而是跟 IoC 容器说:我要一个 IB(getBean("IB"))。然后,由容器根据配置文件来做具体的 new 的工作。具体 new 的是哪个,由配置文件从代码外部决定,要更换成 B,B1,或是 B2...修改配置文件就能做到,不用再改代码了
59.什么是 AOP
AOP: 面向切面编程:Aspect Oriented Programming
AOP 是 OOP 的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面编程。
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑
可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
AOP 实际是 GoF 设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP 可以说也是这种目标的一种实现。
在 Spring 中提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。
它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
应用举例:
假设有在一个应用系统中,有一个共享的数据必须被并发同时访问,首先,将这个数据封装在数据对象中,称为 Data Class,同时,将有多个访问类,专门用于在同一时刻访问这同一个数据对象。
为了完成上述并发访问同一资源的功能,需要引入锁 Lock 的概念,也就是说,某个时
刻,当有一个访问类访问这个数据对象时,这个数据对象必须上锁 Locked,用完后就立即解锁 unLocked,再供其它访问类访问。
使用传统的编程习惯,我们会创建一个抽象类,所有的访问类继承这个抽象父类,如下:
abstract class Worker{
abstract void locked();
abstract void accessDataObject();
abstract void unlocked();
}
我注:由上面这些题,可以看出,思想很重要,只有琢磨思想和原理的人才能很好地回答这些问题!
2 题的答案:
String str = “xafdvs”;
char[] arr1 = str.toCharArray();
char[] arr2 = Arrays.copyOf(arr1,arr1.length); for(int i=0;i<arr1.length-1;i++){
for(int j = i+1;j<arr2.length;j++){ syso: arr1[i] + “,” + arr2[j];
}
}
3.题的答案:
1.概念介绍:所谓 AOP,即 Aspect orientied program,就是面向方面的编程,
2.解释什么是方面:贯穿到系统的各个模块中的系统一个功能就是一个方面,比如,记录日志,统一异常处理,事务处理,全限检查,这些功能都是软件系统的一个面,而不是一点,在各个模块中都要出现。
3.什么是面向方面编程:把系统的一个方面的功能封装成对象的形式来处理
4.怎么进行面向方面编程:把功能模块对应的对象作为切面嵌入到原来的各个系统模块中,采用代理技术,代理会调用目标,同时把切面功能的代码(对象)加入进来,所以,
用 spring 配置代理对象时只要要配两个属性,分别表示目标和切面对象(Advisor)。
60.Springmvc和Struts2的区别?
机制 :
Springmvc的入口是servlet, Struts2的入口是filter.
性能 :
Springmvc会比struts2快一点。Springmvc是基于方法设计,
Struts2是基于类,每次发一次请求都会实例一个Action,每个Action都会被注入属性。
参数传递:
Struts2是在接受参数的时候,可以采用属性来接收参数,这家说明可以让多个方法共享
拦截器机制:
Struts2有自己的interceptor机制,Springmvc用的是独立的AOP方式,strtus2的配置文件还是比Springmvc大,Springmvc使用简洁,Springmvc比struts2开发效率要高.
62.Struts2工作原理?
参考: https://blog.youkuaiyun.com/qq_37230121/article/details/80229927
、
关于图中的Key:
- Servlet Filters:过滤器链,客户端的所有请求都要经过Filter链的处理。
- Struts Core:Struts2的核心部分,但是Struts2已经帮我们做好了,我们不需要去做这个
- Interceptors,Struts2的拦截器。Struts2提供了很多默认的拦截器,可以完成日常开发的绝大部分工作;而我们自定义的拦截器,用来实现实际的客户业务需要的功能。
-
User Created,由开发人员创建的,包括struts.xml、Action、Template,这些是每个使用Struts2来进行开发的人员都必须会的。
- 1.FilterDispatcher是整个Struts2的调度中心,也就是MVC中的C(控制中心),根据ActionMapper的结果来决定是否处理请求,如果ActionMapper指出该URL应该被Struts2处理,那么它将会执行Action处理,并停止过滤器链上还没有执行的过滤器。
- 2.ActionMapper 会判断这个请求是否应该被Struts2处理,如果需要Struts2处理,ActionMapper会返回一个对象来描述请求对应的ActionInvocation的信息。
- 3.ActionProxy,它会创建一个ActionInvocation实例,位于Action和xwork之间,使得我们在将来有机会引入更多的实现方式,比如通过WebService来实现等。
- 4.ConfigurationManager是xwork配置的管理中心,可以把它看做struts.xml这个配置文件在内存中的对应。
- 5.struts.xml,是开发人员必须光顾的地方。是Stuts2的应用配置文件,负责诸如URL与Action之间映射关系的配置、以及执行后页面跳转的Result配置等。
- 6.ActionInvocation:真正调用并执行Action,它拥有一个Action实例和这个Action所依赖的拦截器实例。ActionInvocation会按照指定的顺序去执行这些拦截器、Action以及相应的Result。
- Interceptor(拦截器):是Struts2的基石,类似于JavaWeb的Filter,拦截器是一些无状态的类,拦截器可以自动拦截Action,它们给开发者提供了在Action运行之前或Result运行之后来执行一些功能代码的机会。
- 7.Action:用来处理请求,封装数据。
二、运行流程
1.当用户的发出请求,比如http:localhost:8080/Struts2/helloworld/helloworldAction.action,请求会被Tomcat接收到,Tomcat服务器来选择处理这个请求的Web应用,那就是由helloworld这个web工程来处理这个请求。
2.Web容器会去读取helloworld这个工程的web.xml,在web.xml中进行匹配,但发现,由struts2这个过滤器来进行处理(也就是StrutsPrepareAndExecuteFilter),根据Filter的配置,找到FilterDispatcher(Struts2的调度中心)
3.然后会获取FilterDispatcher实例,然后回调doFilter方法,进行真正的处理
PS:FilterDispatcher是任何一个Struts2应用都需要配置的,通常情况下,web.xml文件中还有其他过滤器时,FilterDispatcher是放在滤器链的最后;如果在FilterDispatcher前出现了如SiteMesh这种特殊的过滤器,还必须在SiteMesh前引用Struts2的ActionContextCleanUp过滤器
对应Struts2的架构图如下
4.这时FilterDispatcher会将请求转发给ActionMapper。ActionMapper负责识别当前的请求是否需要Struts2做出处理。ActionMapper就类似于公司的保安,来识别是不是当前客户是不是我公司的人
对应Struts2的架构图如下
5.如果需要Struts2处理,ActionMapper会通知FilterDispatcher,需要处理这个请求,FilterDispatcher会停止过滤器链以后的部分,(这也就是为什么,FilterDispatcher应该出现在过滤器链的最后的原因)。然后建立一个ActionProxy实例,这个对象作为Action与xwork之间的中间层,会代理Action的运行过程。
对应Struts2的架构图如下
6.ActionProxy对象在被创建出来的时候,并不知道要运行哪个Action,它手里只有从FilterDispatcher中拿到的请求的URL。
而真正知道要运行哪个Action的是ConfigurationManager。因为只有它才能读取我们的strtus.xml
(在服务器启动的时候,ConfigurationManager就会把struts.xml中的所有信息读到内存里,并缓存,当ActionProxy带着URL向他询问要运行哪个Action的时候,就可以直接匹配、查找并回答了)
对应Struts2的架构图如下
->
7.ActionProxy知道自己该干什么事之后(运行哪个Action、相关的拦截器以及所有可能使用的result信息),然后马上建立ActionInvocation对象了,ActionInvocation对象描述了Action运行的整个过程。
注意:Action完整的调用过程都是由ActionInvocation对象负责
对应Struts2的架构图如下
8.在execute方法之前,好像URL请求中的参数已经赋值到了Action的属性上,这就是我们的"雷锋"—拦截器。
拦截器的运行被分成两部分,一部分在Action之前运行,一部分在Result之后运行,而且顺序是刚好反过来的。也就是在Action执行前的顺序,比如是拦截器1、拦截器2、拦截器3,那么运行Result之后,再次运行拦截器的时候,顺序就变成拦截器3、拦截器2、拦截器1了。
这就好比,你要去奶奶家,需要通过 水泊梁山->盘丝洞 -> 索马里,到了奶奶家,看奶奶回来的时候,就必须要通过 索马里 -> 盘丝洞 -> 水泊梁山。
所以ActionInvocation对象执行的时候需要通过很多复杂的过程,按照指定拦截器的顺序依次执行。
对应Struts2的架构图如下
9.到了奶奶家,然后执行Action的execute方法
10.然后根据execute方法返回的结果(Result),去struts.xml中匹配选择下一个页面
11.根据结果(Result)找到页面后,在页面上(有很多Struts2提供的模板),可以通过Struts2自带的标签库来访问需要的数据,并生成最终页面
注意:这时还没有给客户端应答,只是生成了页面
12.最后,ActionInvocation对象倒序执行拦截器,从奶奶家回来
13.ActionInvocation对象执行完毕后,已经得到响应对象(HttpServletResponse)了,最后按与过滤器(Filter)配置定义相反的顺序依次经过过滤器,向客户端展示出响应的结果
客户端初始化一个执行servlet的请求
这个请求经过一系列的过滤器,被FilterDispatcher调用,询问ActionMapper来决定是否调用Action
FilterDispatcher把请求的处理交给ActionProxy
ActionProxy通过Configuraction Manager询问相关的配置文件,找到需要的Action类
ActionProxy创建ActionInvocation的实例
ActionInvocation调用Action前后的拦截器
Action执行完毕后,根据struts.xml配置文件找到对应的视图页面
63.Hibernate 工作原理?
hibernate工作原理:
1.通过Configuration config = new Configuration().configure();//读取并解析hibernate.cfg.xml配置文件
2.由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>读取并解析映射信息
3.通过SessionFactory sf = config.buildSessionFactory();//创建SessionFactory
4.Session session = sf.openSession();//打开Sesssion
5.Transaction tx = session.beginTransaction();//创建并启动事务Transation
6.persistent operate操作数据,持久化操作
7.tx.commit();//提交事务
8.关闭Session
9.关闭SesstionFactory
为什么要用hibernate:
1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
4. hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。
- 读取并解析配置文件
- 创建SessionFactory
- 打开Session
- 创建事务:transaction
- 持久化操作
- 提交事务
- 关闭Session
- 关闭SessionFactory
64.为什么要用Spring?
Spring能够很好的和各大框架整合
Spring 通过IOC容器管理了对象的创建和销毁 工厂模式
在使用hibernate,mybatis的时候,不用每次都编写提交的事务的代码,可以使用spring的AOP来管理事务 AOP其实就是一个动态代理的实现
声明式事务和编程式事务
65.mybatis的优缺点?
优点:
SQL写在XML中,便于统一管理和优化
提供映射标签,支持对象和数据库的orm字段关系映射
可以对SQL进行优化
缺点:
SQL工作量大
mybagtis移植姓不好
不支持级联
66.谈谈SSH整合?
struts(表示层)+spring(业务层)+hibernate(持久层)
struts是一个表示层的框架,主要用于接收请求,分发请求。struts其实属于MVC中的VC层次的
hibernate是一个持久层的框架,主要负责与关系数据库的操作
spring是一个业务层的框架,是一个整合的框架,能够很好的黏合表示层和持久层。
67.SpringMVC和Struts2的区别
- SpringMVC的方法级别的拦截,Struts2是类级别的拦截;
- SpringMVC是基于Servlet实现Controller,Struts2是基于Filter实现;
- SpringMVC性能和安全性高于Struts2;
- SpringMVC更加组件化和流程化,易于扩展,比如返回JSON通过设置@ResponseBody即可;
- Struts2更加无耦合,比较纯粹,但是需要更多的自行开发的代码以支持更多功能。
68.spring事务隔离级别(五种面试最好全部说出来)
a、DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
b、未提交读(read uncommited) : 脏读,不可重复读,虚读都有可能发生 。是最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。
c、已提交读 (read commited): 避免脏读。但是不可重复读、虚读有可能发生 。保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。Oracle 默认
d、可重复读 (repeatable read): 这种事务隔离级别可以防止脏读,不可重复读。但是可能会出现幻象读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了以下情况产生(不可重复读)。Mysql 默认
e、串行化的 (serializable) : 这是花费最高代价、效率差但最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读之外,还避免了幻象读(避免三种)。
69.Spring事务特性(四种面试最好全部说出来)
原子性 (Atomicity): 一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做要么全不做。
一致性 (Consistency): 事务的执行的前后数据的完整性保持一致.
隔离性 (Isolation): 一个事务执行的过程中,不应该受到其他事务的干扰
持久性(Durability) : 一个事物一旦提交,它对数据库的改变就是永久的
70.Spring事务七个传播特性(七种面试说一两个即可)
a .Propagation.REQUIRED (默认) 面试必须说出来这个。
调用方已经存在事务,则加入到同一个事务中运行,否则,自启一个事务
b .Propagation.REQUIRES_NEW
无论何时自身都会开启新事务
c .Propagation.SUPPORTS
调用方存在事务,则加入到同一个事务中运行,若不存在事务,则以非事务的方式运行
d .Propagation.NOT_SUPPORTED
调用方存在事务,则会被挂起,直到被调用方运行完毕后,事务恢复。
e .Propagation.MANDATORY
调用方存在事务,则加入到同一个事务中运行,若不存在,则抛出异常
f .Propagation.NEVER
调用方存在事务,则抛出异常
g .Propagation.NESTED
若调用方存在事务,则运行一个嵌套事务,若调用方不存在事务,则以Propagation.REQUIRED的方式运行,即开启一个新的事务
71.Hibernate与MyBatis的比较
- Hibernate完全实现对象关系映射(ORM),MyBatis实现的是SQL Mapping
- MyBatis可以进行更为细致的SQL优化,可以减少查询字段。比Hibernate容易掌握,Hibernate门槛较高。
- Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。
- Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。
- Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
- Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。
Spring/Spring Boot中使用@Async
当我们在调用某些耗时的方法,比如发起第三方调用时而不关心他的返回值,可以采用@Async来实现异步调用。
极大的提升程序的响应速度。
在以往的编程方法中我们一般都是开启另一个线程去处理类似的场景,而在Spring 3.x之后则可以使用@Async。
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {
String value() default "";
}
可以看到@Async可以修饰在方法和类上。当修饰方法时,该方法则成为异步方法,这些方法在执行的时候将会被独立的线程去执行。
在Spring和Spring Boot中启用@Async
在启动类上添加注解:@EnableAsync
在相应的方法上添加注解:@Async
需要处理返回值
如果在使用了@Async的方法时还需要处理它的返回值,那么需要用到Future类。
@Async
public Future<String> asyncMethodWithReturnType() {
System.out.println("Execute method asynchronously - "
+ Thread.currentThread().getName());
try {
Thread.sleep(5000);
return new AsyncResult<String>("hello world !!!!");
} catch (InterruptedException e) {
//
}
return null;
}
以上是异步方法,调用该方法时应该以如下方式调用:
public void testAsyncAnnotationForMethodsWithReturnType() throws InterruptedException, ExecutionException {
System.out.println("Invoking an asynchronous method. " +Thread.currentThread().getName());
Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();
while (true) { ///这里使用了循环判断,等待获取结果信息
if (future.isDone()) { //判断是否执行完毕
System.out.println("Result from asynchronous process - " + future.get());
break;
}
System.out.println("Continue doing something else. ");
Thread.sleep(1000);
}
}
通过while true来循环判断异步方法是否正常返回,但是这样的代码在正常情况下完全没有必要性,不如直接写成同步调用。
异常处理
在异步方法中,如果出现了异常,对于调用者而言是无法感知的。如果确实需要处理异常,则需要自定义实现AsyncTaskExecutor。
事务处理
如果想要在异步方法中实现事务,则需要把需要事务管理的方法放到异步方法内部,在内部被调用的方法上添加@Transactional。
例如:
方法A,使用了@Async/@Transactional来修饰,但是无法达到事务控制的目的。
方法B,使用了@Async修饰,B中调用了C、D,C/D分别使用@Transactional来修饰,可以达到事务控制的目的。
@Resource,@Autowired,@Inject 这3种都是用来注入bean的,它们属于不同的程序中。
ANNOTATION | PACKAGE | SOURCE |
---|---|---|
@Resource | javax.annotation | Java JSR-250 |
@Inject | javax.inject | Java JSR-330 |
@Autowired | org.springframework.bean.factory | Spring 2.5+ |
JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。
区别
@Resource
它有两个关键的属性:name-名称,type-类型
1、如果指定了name,type,则从Spring容器中找一个名称和类型相当应的一个bean,找不到则报错。
2、如果只指定了name,则从Spring容器中找一个名称和name一样的bean,找不到则报错。
3、如果只指定了type,则从Spring容器中找一个类型和type一样的bean,找不到或者找到多个则报错。
4、如果没有指定参数,则默认找字段名称装配,找不到则按类型装配,找不到则报错。
@Autowired
默认按类型装配,找不到或者找到多个则报错。
如果要按名称装配,需要结合Spring另外一个注解Qualifier("name")使用。
默认必须装配requred=true,如果可以为空,可以设置为false,在Spring4+结合jdk8+的情况下还可以使用Optional和false同等的效果,如
@Autowired
private Optional<UserService> userService;
@Inject
和@Autowired类似,可以完全代替@Autowired,但这个没有required属性,要求bean必须存在。
如果要按名称装配,需要结合javax另外一个注解N("name")使用。
Spring开启方法异步执行
@EnableAsync注解即开启Spring对方法异步执行的能力,需要和注解@Configuration配合使用。
也可以自定义线程池
@Async
在要异步执行的方法上使用@Async注解,下面是一个没有返回值,一个带有返回值的异步调用的示例。
测试代码
注意事项
1、使用注意
@Async只能使用到被代理的对象方法上,即代理类的入口方法处,且方法必须是public的。
2、事务处理机制
使用@Async异步注解不能和@Transaction事务注解在同一个方法上同时使用,不然事务注解将无效。
要使用事务,需要把事务注解提取到方法里面的子方法上。