1、什么是spring-IOC和DI
可以简单的理解为springIoc和DI都是一种思想,而DI是springIoc的具体实现。以往我们创建对象都需要通过new关键字进行对象的创建,随着对象的依赖关系逐渐复杂,new的方式让代码显得更加繁琐。而springIoc(控制反转)的出现可以让开发者只关注代码逻辑的开发,而将所有的对象统一交给Spring容器进行管理,而spring容器管理对象的方式就是通过DI达到的,DI(依赖注入)的方式有三种:Setter、构造方法、接口;具体实现可参照:Spring-Ioc-DI的三种注入方式:_暇光署墨的博客-CSDN博客_spring ioc注入的三种方式
2、spring支持的几种bean的作用域
- singleton:使用该属性定义bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例
- prototype:使用该属性定义bean时,IOC容器可以创建多个Bean实例,每次返回都是一个新的Bean实例
- request:该属性仅对http请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,使用WebApplicationContext环境
- session:该属性仅使用于HTTP session,同一个session共享一个Bean实例,不同的session使用不同的实例
- global-session:该属性仅使用于HTTP session,同session不同的是,不同的session共享同一个实例
3、spring框架中的单例bean是线程安全的吗
spring的Bean默认是单例模式的,单例bean是指IOC容器中就只有这么一个bean,是全局共享的,有多少个线程来访问用的都是这个bean。由于框架并没有对bean进行多线程的封装处理,所以单例模式的bean不是线程安全的;最简单的办法就是改变bean的作用域 把 "singleton"改为’‘protopyte’ 这样每次请求Bean就相当于是 new Bean() 这样就可以保证线程的
安全了。
4、 spring自动装配的Bean有哪些方式?
spring 配置文件中 节点的 autowire 参数可以控制 bean 自动装配的方式:
- default - 默认的方式和 “no” 方式一样
- no - 不自动装配,需要使用 节点或参数
- byName - 根据名称进行装配
- byType - 根据类型进行装配
- constructor - 根据构造函数进行装配
5、JDK动态代理和CGLIB动态代理区别
JDK动态代理的实现是通过被代理对象实现的接口产生其代理对象的;带定义getProxy()方法的时候通过类加载器获取被代理对象实现的接口,通过被代理对象的类加载器以及实现的接口创建并返回代理对象。
CGLIB动态代理是通过创建被代理对象的子类来创建代理对象的;在定义getProxy()方法的时候,代理对象是通过创建并代理的子类来创建的,使用Enhancer来创建对象,并制定父类,并进行setCallBack进行回调,使用create()创建并返回getProxy。
spring底层会根据类是否实现接口来进行判断,是使用jdk还是cglib。
6、什么是AOP?你们项目中有没有使用到AOP
AOP(面向切面编程),是一种“横切”的技术(底层实现是动态代理),对原油的业务逻辑进行拦截,并对原有的业务逻辑进行增强,在不改变原有业务的情况下对业务逻辑进行增强。有几个名词专有名词要注意:
JoinPoint-连接点:在应用执行过程中能够插入切面(Aspect)的一个点
Pointcut-切入点:实际被增强的方法,就是切入点,比如说有俩方法,一个方法被增强了一个没被增强,则被增强的方法叫做切入点,没被增强的方法就不能叫做切入点
通知/增强:真正被增强的逻辑部分称为通知
切点:添加到切入点的新增的业务方法
切面:定义切点方法的类
使用场景:异常处理、事务提交/回滚、检验是否登陆
7、SpringMvc执行流程
1、前端发送请求被前端控制器DispatcherServlet拦截
2、前端控制器调用处理器映射HandlerMapping对请求URL进行解析,解析之后返回给前端控制器
3、前端控制器调用处理器适配器处理调用链
4、处理器适配器基于反射通过适配器设计模式完成处理器(控制器)的调用,处理用户请求
5、处理器适配器将控制器返回的视图和数据信息封装成ModelAndVIew响应给前端控制器
6、前端控制器调用视图解析器ViewResolve对ModelAndView进行解析,将解析结果(视图资源和数据)响应给前端控制器
7、前端控制器调用视图view组件将数据进行渲染,将渲染的结果(静态资源)响应给前端控制器
8、前端控制器响应用户请求
9、mybatis #{}和${}的区别
#{}:
(1)、编译好SQL后语句再去取值
(2)、将传入的数据都当成一个字符串,会对传入的变量自动加一个单引号。如:user_id = #{userId},如果传入的值是111,那么解析成sql时的值为user_id = ‘111’,如果传入的值是id,则解析成的sql为user_id = ‘id’。
(3)、参数占位符,即预编译
${}:
(1)取值以后再去编译SQL语句
(2)将传入的参数直接显示生成在sql中,且不加任何引号。如:user_id = ${userId},如果传入的值是111,那么解析成sql时的值为user_id = 111 , 如果传入的值是id,则解析成的sql为user_id = id。
(3)字符串替换符,即SQL拼接
10、Mybatis如何获取生成的主键
自增主键:
第一种方式是使用
useGeneratedKeys + keyProperty
组合的方式,其中userGeneratedKeys代表是告诉mybatis要使用自增生成的主键,keyProperty是告诉mybatis主键字段是哪个,如下:<insert id="insert" parameterType="Person" useGeneratedKeys="true" keyProperty="id"> INSERT INTO person(name, pswd) VALUE (#{name}, #{pswd}) </insert>
第二种方式是通过
<selectKey>
来指定sql语句获取生成的主键ID,如下:<insert id="insert" parameterType="Person"> <selectKey keyProperty="id" resultType="long" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO person(name, pswd) VALUE (#{name}, #{pswd}) </insert>
11、当实体类中的属性名和表中的字段名不一样怎么办 ?
第 1 种: 通过在查询的 sql 语句中定义字段名的别名,让字段名的别名和实体类 的属性名一致。
<select id=”selectorder” parametertype=”int” resultetype=”me.gacl.domain.order”> select order_id id, order_no orderno ,order_price price form orders where order_id=#{id}; </select>
第 2 种: 通过来映射字段名和实体类属性名的一一对应的关系。
<select id="getOrder" parameterType="int" resultMap="orderresultmap"> select * from orders where order_id=#{id} </select> <resultMap type=”me.gacl.domain.order” id=”orderresultmap”> <!–用 id 属性来映射主键字段–> <id property=”id” column=”order_id”> <!–用 result 属性来映射非主键字段,property 为实体类属性名,column为数据表中的属性–> <result property = “orderno” column =”order_no”/> <result property=”price” column=”order_price” /> </reslutMap>
12、mybatis如何实现多表查询
在实体类中加入对应的关联查询的字段或集合;
(1)、一对多的关系映射使用的是collection
(2)、一对一的关系映射使用的是association
13、mybatis都有哪些动态sql?能简述一下动态SQL的执行原理嘛?
1、Mybatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能。
2、Mybatis 提 供 了 9 种 动 态 sql 标 签 : trim|where|set|foreach|if|choose|when|otherwise|bind。
3、其执行原理为,使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql,以此来完成动态 sql 的功能。
14、mybatis是否支持延迟加载?
(1)支持!MyBatis 有两种加载方式:立即加载和延迟加载。
MyBatis 只支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的是一对一关联查询的,collection 指的是一对多关联查询。
(2)在 MyBatis 配置文件中,有两种方式可以配置是否启用延迟加载:
第一种是在配置文件的 <settings> 标签中为所有嵌套查询设为延迟加载
第二种是在 <association>、<collection > 中添加 < fetchType > 设置
<settings> <!--2.开启延迟加载--> <!--(1)此方式为:设置所有的分解式(N+1)查询都为延迟加载: 注意:这种方式很少使用,因为不可能为所以分解式查询都设置为延迟加载--> <setting name="lazyLoadingEnabled" value="true"/> <!--(2)此方式为:映射文件中<collection>或<association>中设置了fetchType的方法触发延迟加载,设置为空字符串即可。--> <setting name="lazyLoadTriggerMethods" value=""/> </settings>
(3)一般情况下,一对多查询使用延迟加载,一对一查询使用立即加载。因为一对多可能有上万甚至更多的数据,如果立即加载的话会很占用空间,所以使用延迟加载;而一对一查询的话,只有一条数据,立即加载也不会有什么影响,所以可以立即加载。
15、如何使用mybatis实现批量插入?
使用Mybatis框架批量插入的3种方法:多次调用insert方法、foreach标签、batch模式
16、mybatis批量插入能否返回主键?
Mybatis在插入单条数据的时候有两种方式返回自增主键:
1、对于支持生成自增主键的数据库:增加 useGenerateKeys和keyProperty ,<insert>标签属性。
2、不支持生成自增主键的数据库:使用<selectKey>标签。
17、mybatis的一级、二级缓存
一级缓存为 sqlsesson 缓存,缓存的数据只在 SqlSession 内有效。在操作数据库的时候需要先创建 SqlSession 会话对象,在对象中有一个 HashMap 用于存储缓存数据,此 HashMap 是当前会话对象私有的,别的 SqlSession 会话对象无法访问。
二级缓存是 mapper 级别的缓存,也就是同一个 namespace 的 mapper.xml ,当多个 SqlSession 使用同一个 Mapper 操作数据库的时候,得到的数据会缓存在同一个二级缓存区域
二级缓存默认是没有开启的。需要在 setting 全局参数中配置开启二级缓存
开启二级缓存步骤:
1、conf.xml 配置全局变量开启二级缓存
<settings> <setting name="cacheEnabled" value="true"/>默认是false:关闭二级缓存 <settings>