【面试题】MyBatis面试题

MyBatis想必大家都比较熟悉了吧,它底层封装了JDBC,用来与数据库进行连接。

这里我主要想讲一下MyBatis和MyBatis-plus,主要是想表达一下,据我的了解,这两个在公司中都有所使用,我只简略的学过MyBatis-plus。最直观的就是通用Mapper,为你省略了dao层的添加。当然,一些复杂的逻辑仍然需要你自定义Mapper。但我感觉plus对数据的操作的api相对以前更加复杂。整体而已,推荐大家深度学习MyBatis,在源码级别的学习中更加直白,简易。对于 MyBatis-plus大家只需要熟练使用常用方法。当然这只是我的一点意见。

1.什么是MyBatis

MyBatis是一款半自动化的ORM(对象关系映射)的软件。内部封装了JDBC,使得程序员在开发过程中省略了创建连接,加载驱动等操作,开发人员只需要关注sql语句本身。 MyBatis通过配置文件或者注解即可将数据库数据与pojo实体类联系起来

解释一下什么是对象关系映射

是一种为了解决关系型数据库数据与简单java对象的映射关系的技术

2.#{}和${}有什么区别

首先,他俩都是为了动态传递参数而存在的,是MyBatis实现动态sql的基础

#{}是预编译处理,将这部分先用?代替,调用PreparedStatement的set方法来赋值
${}是字符串替换,直接将这部分用括号内的实际内容代替

3.请说说MyBatis的工作原理

我们在实际开发过程中,都写过MyBatis的配置文件,对于 MyBatis的底层具体实现,就是从这里开始的。
1)读取MyBatis配置文件:mybatis-config.xml为MyBatis的全局配置文件,包含了MyBatis行为的设置和属性信息,例如数据库连接信息和映射文件

2)加载mapper.xml(SQL映射文件):该文件配置了操作数据库的SQL语句

3)构建会话工厂:创建会话工厂SqlSessionFactory

4)创建会话对象:由会话工厂生产sqlSession对象,该对象包含了执行sql语句的所有方法

5)Executor执行器:它将跟据sqlSession传递的参数动态的生成需要执行的sql语句,同时负责查询缓存的维护

6)MappedStatement对象:该对象是对映射信息的封装,用于存储要映射的SQL语句的id,参数等信息

7)输入参数映射:类似于JDBC对preparedStatement对象设置参数的过程

8)输出结果映射:类似于JDBC对结果集的解析过程

4.MyBatis是如何进行分页的?分页原理是什么

通过RowBounds进行逻辑分页。

物理分页:通过数据库limit

逻辑分页:通过代码实现。先查询出所有的数据,再跟据代码块的所需进行分页

还可以通过插件,例如Pagehepler

5. MyBatis是否支持延迟加载?如果支持,实现原理是什么

支持。

这个举例子再生活形象不过,就像用户与订单的关系,我们在用户中包含了订单的集合,但在显示时不会直接显示出来,但当用户点击订单时,再去查询,显示出来订单。这样可以减少数据库的压力。

实现原理:使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,把关联对象查询出来赋值。

6. MyBatis一二级缓存

一级缓存:sqlSession级别的缓存,sqlSession里的HashMap对查询过一次的数据进行存储,如果发出数据库增上改查的操作则取消存储
二级缓存:Mapper级别的,多个sqlSession去操作同一个Mapper的sql语句,多个sqlSession可以共用二级缓存
重要:其实解释到这里,对一些没看过源码的人来说并不友好,下面我对这些东西尽量给大家通俗的讲出来:

首先,session大家应该都了解,我们在Java Web的学习过程中接触过,它代表的是一次浏览器和服务器的交互的会话

sqlSession也是一个会话,每次连接一个数据库就会产生一个sqlSession会话。

下面截取了sqlSession的部分源码,sqlSession里封装了操作数据库的所有操作,还包括了Mapper代理对象

一级缓存:sqlSession级别的,也就是参数和sql语句完全一样的情况下,不需要再次查询数据库,那具体该如何判断呢

如果sqlSession调用了close()方法,会释放掉一级缓存

二级缓存:多个sqlSession可以共享一个mapper中的二级缓存区域,并且如果两个mapper的namespace相同,即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域

下面我们以开启二级缓存进行测试

public class TestStudent extends BaseTest {

public static void selectAllStudent() {
    SqlSessionFactory sqlSessionFactory = getSession();
    SqlSession session = sqlSessionFactory.openSession();
    StudentMapper mapper = session.getMapper(StudentMapper.class);
    List<Student> list = mapper.selectAllStudents();
    System.out.println(list);
    //一级缓存测试
    List<Student> list2 = mapper.selectAllStudents();
    System.out.println(list2);
    session.commit();
    //创建了第二个sqlSession
    //二级缓存测试
    SqlSession session2 = sqlSessionFactory.openSession();
    StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
    List<Student> list3 = mapper2.selectAllStudents();
    System.out.println(list3);
    System.out.println("第二次执行");
    List<Student> list4 = mapper2.selectAllStudents();
    System.out.println(list4);
    session2.commit();

}

public static void main(String[] args) {
    selectAllStudent();
}

}
我们调用了4次 selectAllStudents() ,但sql语句只执行了一次,两次为一级缓存,一次为二级缓存

7. MyBatis编程步骤

1)创建sqlSessionFactory对象

2)生产sqlSession对象

3)获取Mapper代理对象

4)执行数据库操作

5)执行成功,提交事务

6)执行失败,回滚事务

7)关闭会话

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

在这里插入图片描述

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

在这里插入图片描述

10. MyBatis如何进行批量操作

在这里插入图片描述

11. MyBatis实现一对一,一对多有几种方式,怎么操作的

联合查询和嵌套查询

联合查询:几个表联合查询,只查询一次,通过在resultMap里面的association,collection节点配置一对一,一对多的类可以完成

嵌套查询:先查一个表,跟据这个表里面的结果的外键id,再去另一个表里面查询数据,也是通过配置association,collection,但另外一个表的查询通过select节点配置

12. MyBatis动态sql是做什么的,都有哪些动态sql,能简述一下动态sql的原理吗

MyBatis动态sql可以让我们在xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能

实现原理:使用OGNL从sql参数对象中的计算表达式的值,跟据表达式的值动态拼接sql,以此来完成动态sql的功能

下面是我动态SQL的一些练习,方便大家理解

//1.if
//跟据username和sex来查询数据。如果username为空,则按sex查询,反之相同

我们先按原版写

select * from user where username = #{username} and sex = #{sex}

这样的话如果出现空值就没法搞了

select * from user where username=#{username}
	<if test="sex != null">
		and sex=#{sex}
	</if>

//2.where
//如果出现以and或or开头的他会剔除掉

select * from user


username=#{username}

	<if test="sex != null">
		and sex=#{sex}
	</if>
	</where>

//3.choose
//choose标签,挺猛的,类似于java的switch,总能利用到一个搜索条件

select * from user



id=#{id}


and username=#{username}


and sex=#{sex}




按照顺序:
如果id不为空,sql语句为:select * from user where id=?
如果id为空,username不为空:select * from user where username=?;

//4.trim
//trim是一个格式化的标记,可以完成set或where标记的功能

select * from user


and username=#{username}


and sex=#{sex}



prefix:前缀
prefixOverrides:去掉第一个and或or

//5.foreach

select * from user



#{id}


13. MyBatis的架构设计是怎样的

1)API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理

2)数据处理层:负责具体的SQL查找,SQL解析,SQL执行和执行结果映射处理。它主要的目的是跟据调用的请求完成一次数据库操作

3)基础支撑层:负责最基础的功能支撑,包括连接管理,事务管理,配置加载和缓存处理,这些都是公用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑

4)引导层:加载xml配置和java配置

14.如何获取生成的主键

insert into user( user_name, user_password, create_time) values(#{userName}, #{userPassword} , #{createTime, jdbcType= TIMESTAMP})

15.当实体类中的属性名和表中的字段名不一样时,怎么办

select * from orders where order_id=#{id} <!–用id属性来映射主键字段–>

<!–用result属性来映射非主键字段,property为实体类属性名,column为数据库表中的属性–>


16.Dao接口的工作原理

Dao接口就是映射文件中的namespace的值,接口的方法名,就射映射文件MappedStatement的id值,接口方法内的参数,就是传递给sql的参数

Dao接口的工作原理就是JDK动态代理,MyBatis运行时会使用JDK动态代理为Dao接口生成代理对象proxy,代理对象会拦截接口方法调用,转而执行方法对应的sql语句,然后将sql执行结果返回

17.简述 MyBatis的插件运行原理,以及如何编写一个插件

Mybatis仅可以编写针对Executor、StatementHandler、ParameterHandler、ResultSetHandler这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。

实现Mybatis的Interceptor接口并重写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,最后在配置文件中配置你编写的插件。

另外,我自定义实现过一个简单的MyBatis,现在太忙了,过段时间给大家详细的讲解如何自定义实现简单的MyBatis。还有就是,我认为MyBatis是最好入门源码阅读的技术栈。我读过不少源码,但大多都理解的不清不楚。相对而言,MyBatis是结构划分最清晰的,整体难度也偏低的。十分推荐通过MyBatis入门阅读源码。后期我应该会上传MyBatis阅读源码的方法,帮助大家入门。

欢迎访问我的个人博客:gaoyuehao.vip。里面有大量的面试题内容哦~

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值