Spring框架概述(介绍)?
Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于XML的配置、基于注解的配置、基于Java的配置。
你都了解哪些 SpringFramework的组件,谈谈他们的作用?
> Spring Core:核心类库,提供IOC服务;
> Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
> Spring AOP:AOP服务;
> Spring DAO:对JDBC的抽象,简化了数据访问异常的处理;
> Spring ORM:对现有的ORM框架的支持;
> Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传;
> Spring MVC:提供面向Web应用的Model-View-Controller实现。
使用Spring框架能带来哪些好处?
> (1)spring属于低侵入式设计,代码的污染极低;
> (2)spring的DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性;
> (3)Spring提供了AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用。
> (4)spring对于主流的应用框架提供了集成支持。
Spring有哪些配置方式?
常见的配置方式有三种:
基于XML的配置、
基于注解的配置(@Component、@Repository、@Controller)、
基于Java类+配置注解的方式(@Configuration @Bean)。
什么是基于注解的容器配置,如何在Spring中启动注解装配?
在Spring的配置文件中 定义注解扫描的范围
<context:component-scan base-package="com.itcast" />
这样 在com.itcast包下的所有标注了 @Component、@Repository、@Controller注解的类,会被注册到容器中
Spring框架中使用到的设计模式?
工厂模式: Spring中的FactoryBean就是典型的工厂方法模式。使用工厂模式创建对象的实例
单例模式:在Spring配置文件中定义的Bean默认为单例模式
模板方法:用来解决代码重复的问题,比如我们常使用的RestTemplate、JmsTemplate、JpaTemplate都是基于模板方法
代理模式: AOP的底层实现就是基于JDK动态代理 及 CGLIB动态代理
观察者模式:Spring中Observer模式常用的地方是listener的实现。如ApplicationListener。
适配器模式:AOP的方法拦截器中
策略模式:Spring中在实例化对象的时候用到Strategy模式
什么是Spring IOC容器?
> (1)IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。
> (2)最直观的表达就是,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。
> (3)Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
什么是依赖注入 ?
DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
DI依赖注入的几种方式?
构造器注入、setter方法注入、根据注解注入
IOC和DI有什么区别
IOC偏向一种思想,对象的创建权,由程序交给了IOC容器,所以叫控制反转,而DI强调的是容器要负责创建对象,但对象在创建时可能需要赋值一些属性,或者依赖其他对象,定义容器内对象时需要定义好这些关系,这样容器在创建对象时就会根据这些关系帮我们自定的设置好属性 或 依赖的对象。 这两实际上都是在介绍容器的功能,只是从不同的方面去解释容器而已。
Spring中有常用的IOC容器,及他们的实现类
> IOC容器的顶级接口 BeanFactory , 仅提供了最基本的容器方法
> ApplicationContext接口 则扩展了BeanFactory,提供了很多功能,使我们常用的容器
> BeanFacotry的实现类 XmlBeanFactory
> ApplicationContext的实现类:
> **ClassPathXmlApplicationContext**:可以加载类路径下的配置文件,实现容器的实例化。
> **FileSystemXmlApplicationContext**:可以加载磁盘任意路径下的配置文件,实现容器的实例化。(必须有访问权限)
> **AnnotationConfigApplicationContext **:扫描配置注解,根据注解配置实现容器的实例化。
配置Bean对象的常用属性?
> **id**标签是bean的唯一标识,IoC容器中bean的id标签不能重复,否则报错。
> **name**是bean的别名,可以定义多个
> **class属性**是bean常用属性,为bean的全限定类名,指向classpath下类定义所在位置
> **factory-method**属性factory-method工厂方法属性,通过该属性,我们可以调用一个指定的静态工厂方法,创建bean实例。
> **scope属性** bean的作用范围
> **init-method和destory-method属性 ** Bean的初始化和销毁时执行的方法
> **autowire属性** 表示bean的自动装配方式 可选值: no:默认,不进行自动装配 .byName .byType
SpringBean对象的作用域?(scope属性的值)
> **singleton**:表示整个IOC容器共享一个Bean,也就是说每次说每次通过getBean获取的bean都是同一个。
> **prototype**:每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。
> **request**:每次HTTP请求将会生成各自的bean实例
> **session**:每次会话请求对应一个bean实例
> **global-session**:全局作用域
> singleton和prototype经常使用,其他的很少使用。
SpringBean对象的生命周期?
> **(1)实例化Bean:**
> 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
> **(2)设置对象属性(依赖注入):**
> 实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
> **(3)处理Aware接口:**
> 接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
> ①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
> ②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
> ③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
> **(4)BeanPostProcessor:**
> 如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
> **(5)InitializingBean 与 init-method:**
> 如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
> **(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;**
> 以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
> **(7)DisposableBean:**
> 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
> **(8)destroy-method:**
> 最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
SpringBean对象是否线程安全?Spring如何处理线程并发问题?
Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
Spring的常用注解?
> @ComponentScan 组件扫描, 会扫描指定包下的 @Component @Controller @Service @Repository
> @Controller 标注当前类为容器的对象,代表控制组件
> @Service 标注当前类为容器的对象,代表服务组件
> @Repository 标注当前类为容器的对象,代表持久组件
> @Component 标注当前类为容器的对象,代表组件
> @Autowired 自动装配注解 默认按类型装配
> @Transactional 事务注解
> @Value 将配置文件中的值,注入到指定字段
> @Bean 配置bean对象 <bean>标签作用一致
> @Configuration 标注当前的java类是一个配置类
PS:@Controller @Service @Component @Repository的区别
- @Component spring基础的注解,被spring管理的组件或bean
- @Repository 用于持久层,数据库访问层
- @Service 用于服务层,处理业务逻辑
- @Controller 用于呈现层,(spring-mvc)
@Autowired和@Resource注解的区别?
> 1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
> 2、 @Autowired默认按类型装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以搭配@Qualifier注解进行使用
> 3、@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
springMVC常用注解
> @RequestMapping 指定请求资源路径**
> @ResponseBody 注解表示将该方法的返回值 直接返回到客户端,一般我们返回的都是 json**
> @RequestBody** 接收前台 json参数
> @RequestParam 接收前台表单参数 key = value 形式参数 ? a=1 & b=2
> @PathVariable 获取路径参数的** http:ip:port/user/111
> @RestController 相当于 @ResponseBody 和 @Controller的合体
> @ControllerAdvice controller的增强注解,用于统一处理功能:如统一异常处理
> @ExceptionHandler 异常处理
> @CookieValue 指定cookie中的参数
> @RequestHeader 指定请求消息头中的参数
什么是Spring的内部Bean
当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,为了定义inner bean,在Spring 的 基于XML的 配置元数据中,可以在 <property/>或 <constructor-arg/> 元素内使用<bean/> 元素,内部bean通常是匿名的,它们的Scope一般是prototype。
IOC容器构建对象的几种方式?
> 1)调用无参数构造器
> 2)带参数构造器
> 3)工厂创建对象
> 工厂类:静态方法创建对象
> 工厂类:非静态方法创建对象
了解Spring的源码吗?IOC容器的初始化流程是怎样的? (简述Spring IOC的实现机制)
结合课件总结话术
什么叫延迟加载
默认情况下,scope位singlton的Spring Bean对象,在容器初始化完毕后会直接加载的,如果需要改成什么时候用什么时候加载,可以修改配置中的 init-lazy属性位true,这样就设置了延迟加载
Spring Bean 怎样解决循环依赖的问题
Spring Bean的Scope为Singleton时,循环依赖问题可以通过三级缓存来解决。
另外不使用构造函数传参的方式,可以改为属性传参 或者 @Autowired注解的方式
项目中使用AOP的场景?
比较常用的 事务、权限、异常、 用户行为日志、 性能监控、缓存等等
用户行为日志:
某时 张三 添加一条用户信息 操作耗时: 电脑IP:
某时 张三 删除一条用户信息 操作耗时: 电脑IP:
某时 张三 修改一条用户信息 操作耗时: 电脑IP:
介绍基本概念
AOP:面向切面编程
简单理解-->
可以让我们把分散到项目中的各种通用性功能抽取出来,
统一在切面类中实现:
举例-->
比如: 通用的异常、权限、日志、事务等等的处理
好处-->
这样可以通过面向切面实现非常好的解耦和 以及统一管理我们的代码
说清楚基本用法
定义切面类 我们使用注解的方式 @Aspect @Component
定义切入点表达式 可以通过 扫描包的方式 也 可以通过指定注解的方式
定义通知: 通知分5种
我们通常使用环绕通知
说清楚底层原理
AOP的底层的工作原理 就是使用动态代理对目标业务进行增强,而动态代理使用的就是JDK 和 CGLIB两种动态代理
使用AOP进行面向切面开发的步骤?(如何实现)
SpringAOP 的底层实现?
SpringAOP的底层主要基于动态代理技术 (JDK动态代理、Cglib动态代理)
介绍一下代理模式?分类?JDK和cglib的区别?
JDK和cglib的具体实现,要求能口述?
代理对象 = Proxy.newInstance(类加载器,目标对象的所有接口,InvocationHandler接口的实例);
Enhancer en = new Enhancer();
en .supperClass();
en.setCallback(); // 实现MethodInteceptor 的实例
代理对象 = en.create();
Spring声明式事务,如何配置
注解方式配置
基于aop的tx标签配置
什么是事务的隔离级别,分成哪些隔离级别
Spring 默认使用数据库的隔离级别
ISOLATION_READ_UNCOMMITTED:读未提交
ISOLATION_READ_COMMITTED:读已提交
ISOLATION_REPEATABLE_READ:可重复读
ISOLATION_SERIALIZABLE:串行化
什么是事务的传播行为,分成哪些传播行为
!! PROPAGATION_REQUIRED
表示当前方法必须在一个具有事务的 上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。( 如果被调用端发生异常,那
么调用端和被调用端事务都将回滚)
PROPAGATION_REQUIRES_NEW
总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
PROPAGATION_SUPPORTS
表示当前方法不必需要具有一个事务 上下文,但是如果有一个事务的话,它也可以在这个事务中运行
PROPAGATION_MANDATORY
表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
PROPAGATION_NOT_SUPPORTED
总是非事务地执行,并挂起任何存在的事务。
PROPAGATION_NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常
PROPAGATION_NESTED
表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中 ,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation. required的一样
什么情况spring中的事务会失效?
1. 数据库引擎不支持事务
2. 没有被Spring管理
3. 方法不是public的
4. 自身调用问题
5. 数据源未配置事务管理
6. 传播行为中设置了不支持事务
7. 异常被捕获掉
8. 异常类型错误, 默认捕获RuntimeException异常
如果throw new Exception则事务失效
SpringMVC的流程?
(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。
SpringMVC与Struts2的区别
(1)springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器(StrutsPrepareAndExecuteFilter)。
(2)springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
(3)Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。
如何解决POST请求中文乱码问题,GET的又如何处理呢?
(1)解决post请求乱码问题:
在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(2)解决get请求乱码问题
String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
-- 原因:
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。
Mybatis面试题汇总
#{}和${}的区别是什么
#{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。
##### 使用建议:
能用 #{} 的地方就用 #{},不用或少用 ${}
表名作参数时,必须用 ${}。如:select * from ${tableName}
order by 时,必须用 ${}。如:select * from t_user order by ${columnName}
使用 ${} 时,要注意何时加或不加单引号,即 ${} 和 '${}'
当实体类中的属性名和表中的字段名不一样,怎么办
> 写sql语句时起别名 ,别名和属性相对应
> 在MyBatis的全局配置文件中开启驼峰命名规则 ,mybatis会将数据库中 下划线的字段自动转为驼峰格式的属性
> 在Mapper映射文件中使用resultMap来自定义映射规则
XML映射文件中,除了常见的Select|insert|update|delete标签之外,还有哪些标签
<if> <choose> <where> <trim> <foreach> <bind> <resultMap> <sql> <collection> ......随便说
动态sql的 foreach标签有哪些属性,如何使用
MyBatis动态SQL是做什么的,有哪些动态SQL,能简述一下动态SQL的执行原理吗
在执行sql语句时会根据 全限类名+方法名(cn.itcast.mapper.UserMapper.findAll)获取到
MappedStatement,
在MappedStatement的getBoundSql中,根据sqlSource把所有sql拼装,并通过SqlSourceBuilder#parse的处理,把sql中的 在得到BoundSql之前,通过SqlNode#apply把sql都拼接起来,然后SqlSourceBuilder会把xml配置的变量处理为sql预执行中的"?",最终构建为sqlsource.进而得到BoundSql,BoundSql包含了sql和变量参数值
通过一个XML映射文件,都会写一个Mapper接口与之对应,请问,这个Mapper接口的工作原理。
回答mybatis的运行原理
Mapper接口里的方法,参数不同时,方法能重载吗
不可以,不论是注解配置的mybatis 还是xml配置的mybatis,被解析后每个方法都会封装成一个MappedStatement 存储到一个map集合中,集合的key使用的是mapper接口的全限类名+方法名,value就是MappedStatement对象。
如:
我想写个重载方法 findUser 一个带ID参数 返回值User 一个不带参数 返回值为List<User> 但是这个方法在map中寻找时都是以 xxx.UserMapper.findUser作为key ,会发生冲突 实际上这个时候mybatis也会报错。
Mapper接口绑定有几种实现方式,分别是怎样实现的
-- 一种是通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定
@Select("select * from `tb_Teacher` where id = #{id}")
public teacher selectTeacherByID(int id);
-- 另外一种就是通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。
<select id="selectUserByID" parameterType="int" resultType="test.student">
select id,name,age,stuCountry stu_country from `tb_Student` where id = #{id}
</select>
MyBatis的XML Mapper文件中,不同的XML映射文件,id是否可以重复
如果是不同的namespace ,定义方法的id是可以重复的,因为mapper接口的方法映射 是全限类名+方法名
如何获取自动生成的(主)键值
1.可以通过查询最后一条的sql语句
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
2.也可以通过mybatis的标签属性 useGeneratedKeys
<insert id="insertSelective" parameterType="cn.tencent.eee.aaa.dao.model.User" useGeneratedKeys="true" keyProperty="id">
</insert>
MyBatis执行批量插入,能返回数据库主键列表吗
// 可以的 设置好useGeneratedKeys 属性 和 keyProperty属性
<insert id="insertBatchIds" useGeneratedKeys="true" keyProperty="id">
insert into t_user_score(user_id,score,created_at) values
<foreach collection="list" item="obj" separator=",">
(#{obj.userId}, #{obj.score}, now())
</foreach>
</insert>
在Mapper中如何传递多个参数
> 通过实体类传参
> 通过map传参
> 通过定义多个@Param注解传参
MyBatis是否可以映射Enum枚举类
可以的**,MyBatis内置了两个枚举转换器分别是:
EnumTypeHandler
这是默认的枚举转换器,该转换器将枚举实例转换为实例名称的字符串,即将UserSex.MALE转换MALE。
EnumOrdinalTypeHandler
顾名思义这个转换器将枚举实例的ordinal属性作为取值,即UserSex.MALE转换为0,UserSex.FEMALE转换为1。
使用它的方式是在MyBatis配置文件中定义:
MyBatis都有哪些Executor执行器,它们之间的区别是什么
SimpleExecutor
简单执行器(默认),每次执行CRUD都会创建一个PreparedStatement去执行sql
ReuseExecutor
可复用的执行,执行CRUD会查看缓存,缓存没有才会创建一个PreparedStatement去执行sql,并缓存该执行对象
BatchExecutor
批处理执行器,用于执行批量处理
MyBatis如何执行批量插入
1.方式1, 通过mybatis的动态标签,已批量新增为例 比较常用
<!-- 批量新增-->
<insert id="batchSave" parameterType="java.util.List">
INSERT INTO lp_user_test_batch
(
id,
user_id,
user_name
)
VALUES
<foreach collection="list" item="item" index="index" separator=",">
(
#{item.id,jdbcType=BIGINT},
#{item.userId,jdbcType=VARCHAR},
#{item.userName,jdbcType=VARCHAR}
)
</foreach>
</insert>
2.利用 MyBatis 批处理特性,批量提交(ExecutorType.BATCH)
public void batchInsert(List<UserTestBatchDO> testBatchDAOList) {
//集合非空
if (CollectionUtils.isEmpty(testBatchDAOList)) {
return;
}
//批处理方式 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
//获得对应的Mapper
UserTestBatchDOMapper userTestBatchDOMapper = sqlSession.getMapper(UserTestBatchDOMapper.class);
try {
for (UserTestBatchDO testBatchDO : testBatchDAOList) {
userTestBatchDOMapper.insert(testBatchDO);
}
//统一提交
sqlSession.commit();
} catch (Exception e) {
//没有提交的数据可以回滚
sqlSession.rollback();
} finally {
//关闭 sqlSession
sqlSession.close();
}
}
简单介绍一下MyBatis的一级缓存和二级缓存的概念和实现原理
一级缓存:默认开启
一级缓存的范围是同一个SqlSession对象,当我们使用SqlSession对象进行查询时mybatis会帮我们把查询的数据存入到内存中,当我们在这个SqlSession中再一次执行同样的查询操作时,我们就可以直接去缓存中获取数据
二级缓存:默认关闭
二级缓存是mapper级别的缓存,多个SqlSession共享,其作用域是mapper的同一个namespace,不同的SqlSession两次执行相同的namespace下的sql语句,且向sql中传递的参数也相同,即最终执行相同的sql语句,则第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。
一级缓存 和 二级缓存的执行顺序
二级缓存 ———> 一级缓存 ——> 数据库
MyBatis能否一对一、一对多的关联查询,都有哪些实现方式,它们之间的区别是什么
在xml中定义映射关系, 使用association代表关联一个实体类, property映射的属性名,javaType该属性的实体类类型,fetchType是否延迟加载,column用于执行select方法所传递的参数,select需要执行的mapper方法的全限定名称
在xml中定义映射关系,因为是一个集合 所以使用collection标签,ofType代表集合中实体类的类型,其他属性和上面对一的情况一致
MyBatis是否支持延迟加载,如果支持,如何实现
> 支持延迟加载
> 在核心配置文件中开启延迟加载
在关联标签中 fetchType 设置为lazy
MyBatis是如何进行分页的,分布插件的原理是什么
可以通过pageHelper插件实现分页
<!-- 配置分页插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库-->
<property name="dialect" value="mysql"/>
</plugin>
</plugins>
PageHelper.startPage(1,1); // 在代码中执行startPage方法 第一个参数第几页,第二个是几条数据
PageHelper分页的实现在我们执行SQL语句之前动态的将SQL语句拼接了分页的语句,从而实现了从数据库中分页获取数据的过程。
MyBatis与Hibernate有哪些不同
(1)Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。
(2)Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。
(3)Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。
MyBatis映射文件中,如果A标签通过include引用了B标签的内容,请问,B标签能否在A标签的后面,还是说必须定义在A标签的前面
可以定义在A标签的后边
简述MyBatis的XML映射文件和MyBatis内部数据结构之间的映射关系
Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部。在Xml映射文件中,<parameterMap>标签会被解析为ParameterMap对象,其每个子元素会被解析为ParameterMapping对象。<resultMap>标签会被解析为ResultMap对象,其每个子元素会被解析为ResultMapping对象。每一个<select>、<insert>、<update>、<delete>标签均会被解析为MappedStatement对象,标签内的sql会被解析为BoundSql对象。
Mybatis中使用到了哪些设计模式
**Builder模式**,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;
**工厂模式**,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;
**单例模式**,例如ErrorContext和LogFactory;
**代理模式**,Mybatis实现的核心,比如MapperProxy、ConnectionLogger,用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;
**装饰者模式**,例如Cache包中的cache.decorators子包中等各个装饰者的实现;
**组合模式**,例如SqlNode和各个子类ChooseSqlNode等;
**模板方法模式**,例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;
**适配器模式**,例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;
**迭代器模式**,例如迭代器模式PropertyTokenizer;