其他分享
首页 > 其他分享> > 彻底搞定MyBatis

彻底搞定MyBatis

作者:互联网

大家好,我是老三,面渣逆袭系列继续,这节我们的主角是MyBatis,作为当前国内最流行的ORM框架,是我们这些crud选手最趁手的工具,赶紧来看看面试都会问哪些问题吧。

 

 

基础

 

 

1.说说什么是MyBatis?

 

 

先吹一下

 

 

 

 

再说一下缺点

 

 

 

 

ORM是什么?

 

 

 

 

为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?

 

 

 

 

JDBC编程有哪些不足之处,MyBatis是如何解决的?

 

 

 

 

2.Hibernate 和 MyBatis 有什么区别?

 

 

PS:直接用Hibernate的应该不多了吧,毕竟大家都是“敏捷开发”,但架不住面试爱问。

 

 

相同点

 

 

 

 

不同点

 

 

 

 

MyBatis和Hibernate的适用场景?

 

 

 

 

3.MyBatis使用过程?生命周期?

 

 

MyBatis基本使用的过程大概可以分为这么几步:

 

 

 

复制代码

 

String resource = "org/mybatis/example/mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

 

 

 

复制代码

 

SqlSession session = sqlSessionFactory.openSession();

 

 

 

 

MyBatis生命周期?

 

 

上面提到了几个MyBatis的组件,一般说的MyBatis生命周期就是这些组件的生命周期。

 

 

 

 

当然,万物皆可集成Spring,MyBatis通常也是和Spring集成使用,Spring可以帮助我们创建线程安全的、基于事务的 SqlSession 和映射器,并将它们直接注入到我们的 bean 中,我们不需要关心它们的创建过程和生命周期,那就是另外的故事了。

 

 

ps:接下来看看Mybatis的基本使用,不会有人不会吧?不会吧!

 

 

4.在mapper中如何传递多个参数?

 

 

方法1:顺序传参法

 

复制代码

 

public User selectUser(String name, int deptId);<select id="selectUser" resultMap="UserResultMap">    select * from user    where user_name = #{0} and dept_id = #{1}</select>

 

 

 

 

方法2:@Param注解传参法

 

复制代码

 

public User selectUser(@Param("userName") String name, int @Param("deptId") deptId);<select id="selectUser" resultMap="UserResultMap">    select * from user    where user_name = #{userName} and dept_id = #{deptId}</select>

 

 

 

 

方法3:Map传参法

 

复制代码

 

public User selectUser(Map<String, Object> params);<select id="selectUser" parameterType="java.util.Map" resultMap="UserResultMap">    select * from user    where user_name = #{userName} and dept_id = #{deptId}</select>

 

 

 

 

方法4:Java Bean传参法

 

复制代码

 

public User selectUser(User user);<select id="selectUser" parameterType="com.jourwon.pojo.User" resultMap="UserResultMap">    select * from user    where user_name = #{userName} and dept_id = #{deptId}</select>

 

 

 

 

5.实体类属性名和表中字段名不一样 ,怎么办?

 

 

 

 

6.Mybatis是否可以映射Enum枚举类?

 

 

 

 

7.#{}和${}的区别?

 

 

 

 

8.模糊查询like语句该怎么写?

 

 

 

复制代码

 

<select id="listUserLikeUsername" resultType="com.jourwon.pojo.User">&emsp;&emsp;<bind name="pattern" value="'%' + username + '%'" />&emsp;&emsp;select id,sex,age,username,password from person where username LIKE #{pattern}</select>

 

 

9.Mybatis能执行一对一、一对多的关联查询吗?

 

 

当然可以,不止支持一对一、一对多的关联查询,还支持多对多、多对一的关联查询。

 

 

 

 

那么多对一、多对多怎么实现呢?还是利用<association>和<collection>,篇幅所限,这里就不展开了。

 

 

10.Mybatis是否支持延迟加载?原理?

 

 

 

 

11.如何获取生成的主键?

 

 

 

 

12.MyBatis支持动态SQL吗?

 

 

MyBatis中有一些支持动态SQL的标签,它们的原理是使用OGNL从SQL参数对象中计算表达式的值,根据表达式的值动态拼接SQL,以此来完成动态SQL的功能。

 

 

![

 

 

 

 

13.MyBatis如何执行批量操作?

 

 

第一种方法:使用foreach标签

 

 

foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach标签的属性主要有item,index,collection,open,separator,close。

 

 

 

 

在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有以下3种情况:

 

 

  1. 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list

  2. 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array

  3. 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,
    map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key

 

 

看看批量保存的两种用法:

 

复制代码

 

<!-- MySQL下批量保存,可以foreach遍历 mysql支持values(),(),()语法 --> //推荐使用<insert id="addEmpsBatch">    INSERT INTO emp(ename,gender,email,did)    VALUES    <foreach collection="emps" item="emp" separator=",">        (#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})    </foreach></insert>

 

复制代码

 

<!-- 这种方式需要数据库连接属性allowMutiQueries=true的支持 如jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true -->  <insert id="addEmpsBatch">    <foreach collection="emps" item="emp" separator=";">                                         INSERT INTO emp(ename,gender,email,did)        VALUES(#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})    </foreach></insert>

 

 

第二种方法:使用ExecutorType.BATCH

 

 

 

 

14.说说Mybatis的一级、二级缓存?

 

 

  1. 一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为SqlSession,各个SqlSession之间的缓存相互隔离,当 Session flush 或 close 之后,该 SqlSession 中的所有 Cache 就将清空,MyBatis默认打开一级缓存。

     

 

 

  1.  

  2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同之处在于其存储作用域为 Mapper(Namespace),可以在多个SqlSession之间共享,并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置。

 

 

原理

 

 

15.能说说MyBatis的工作原理吗?

 

 

我们已经大概知道了MyBatis的工作流程,按工作原理,可以分为两大步:生成会话工厂会话运行

 

 

MyBatis是一个成熟的框架,篇幅限制,这里抓大放小,来看看它的主要工作流程。

 

 

构建会话工厂

 

 

构造会话工厂也可以分为两步:

 

 

 

 

会话运行

 

 

会话运行是MyBatis最复杂的部分,它的运行离不开四大组件的配合:

 

 

 

 

整体上总结一下会话运行:

 

 

PS:以上源码分析比较简单,在真正的源码大佬面前可能过不了关,有条件的建议Debug一下MyBatis的源码。

 

 

我们最后把整个的工作流程串联起来,简单总结一下:

 

 

  1. 读取 MyBatis 配置文件——mybatis-config.xml 、加载映射文件——映射文件即 SQL 映射文件,文件中配置了操作数据库的 SQL 语句。最后生成一个配置对象。

  2. 构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。

  3. 创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。

  4. Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。

  5. StatementHandler:数据库会话器,串联起参数映射的处理和运行结果映射的处理。

  6. 参数处理:对输入参数的类型进行处理,并预编译。

  7. 结果处理:对返回结果的类型进行处理,根据对象映射规则,返回相应的对象。

 

 

16.MyBatis的功能架构是什么样的?

 

 

我们一般把Mybatis的功能架构分为三层:

 

 

 

 

17.为什么Mapper接口不需要实现类?

 

 

四个字回答:动态代理,我们来看一下获取Mapper的过程:

 

 

 

 

18.Mybatis都有哪些Executor执行器?

 

 

Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。

 

 

 

 

作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。

 

 

Mybatis中如何指定使用哪一种Executor执行器?

 

 

 

 

插件

 

 

19.说说Mybatis的插件运行原理,如何编写一个插件?

 

 

插件的运行原理?

 

 

Mybatis会话的运行需要ParameterHandler、ResultSetHandler、StatementHandler、Executor这四大对象的配合,插件的原理就是在这四大对象调度的时候,插入一些我我们自己的代码。

 

 

Mybatis使用JDK的动态代理,为目标对象生成代理对象。它提供了一个工具类Plugin,实现了InvocationHandler接口。

 

 

使用Plugin生成代理对象,代理对象在调用方法的时候,就会进入invoke方法,在invoke方法中,如果存在签名的拦截方法,插件的intercept方法就会在这里被我们调用,然后就返回结果。如果不存在签名方法,那么将直接反射调用我们要执行的方法。

 

 

如何编写一个插件?

 

 

我们自己编写MyBatis 插件,只需要实现拦截器接口 Interceptor (org.apache.ibatis. plugin Interceptor ),在实现类中对拦截对象和方法进行处理。

 

 

 

复制代码

 

<plugins>    <plugin interceptor="xxx.MyPlugin">       <property name="dbType",value="mysql"/>    </plugin></plugins>

 

 

20.MyBatis是如何进行分页的?分页插件的原理是什么?

 

 

MyBatis是如何分页的?

 

 

MyBatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

 

 

分页插件的原理是什么?

 

 

 

 

可以看一下一个大概的MyBatis通用分页拦截器:

 

 

标签:搞定,映射,彻底,对象,代码,复制,SQL,MyBatis
来源: https://www.cnblogs.com/piaobodeyun0000/p/16140034.html