6、Mybatis面试题小结

面试题总结 专栏收录该内容
9 篇文章 0 订阅

文章目录

1. 如何理解Mybatis?

这里我们先看看什么是ORM

ORM(Object Relational Mapping)

ORM:是对象关系映射的意思,它是一种思想,是将数据库中的每一行数据用对象的形式表示出来

Mybatis

  • Mybatis是一个Java的持久层框架,它的内部封装了JDBC使得开发者只需要关注 sql 语句本身,而不需要去花费精力处理加载驱动、创建连接、创建 statement 等繁杂的过程,

  • Mybatis 采用ORM思想解决实体和数据库映射的问题,简单的说就是把数据库表和实体类及实体类的属性对应起来


2. 为什么说Mybatis是半自动ORM映射工具?

Mybatis 在查询关联对象时,需要在xml中手动编写sql语句来完成,所以称之为半自动ORM映射工具


3. JDBC 编程回顾

  • 加载驱动:Class.forName("com.mysql.jdbc.Driver")
  • 获取连接:DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis", "root", "root")
  • 创建sql语句,带有占位符String sql = "select * from user where username = ?";
  • 执行sql语句,获取PrepareStatement对象:ps = conn.prepareStatement(sql);
  • 处理结果集:ps.executeQuery();
  • 关闭资源

4. JDBC开发有哪些不足,Mybatis中是如何解决的?

  1. 频繁创建数据库连接对象、释放容易造成系统资源浪费,影响系统性能
    解决方案:在mybatis-config.xml中配置数据库连接池,使用连接池管理数据库连接

  2. Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码
    解决方案:将sql语句编写在XXXmapper.xml文件中与java代码分离

  3. 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应
    解决方案:Mybatis自动将java对象映射至sql语句

  4. 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便
    解决方案:Mybatis自动将sql执行结果映射至java对象


5. Mybatis的优点和缺点

优点:

  • 基于sql语句编程,灵活,不会对应用程序或者数据库的现有设计造成任何影响;sql 写在xml 里,解除sql 与程序代码的耦合,便于统一管理;提供 xml 标签,支持编写动态 sql 语句,并可重用
  • 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接
  • 很好的与各种数据库兼容(底层还是JDBC连接数据库,所以JDBC支持的数据库 Mybatis 都支持)
  • 能够与Spring很好的集成
  • 提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象关系映射
    标签,支持对象关系组件维护

缺点:

  • 当字段多、关联表多时,sql 语句的编写量较大,要求开发人员编写sql语句的功底要强
  • sql 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库

6. Mybatis的编写步骤

  1. 创建 SqlSessionFactory
  2. 通过SqlSessionFactory创建SqlSession
  3. 通过SqlSession来执行数据库的操作
  4. 调用session.commit()提交事务
  5. 调用session.close()来关闭会话

7. Mybatis的工作原理在这里插入图片描述

  1. 读取 Mybatis 配置文件:mybatis-config.xml 为 Mybatis 的全局配置文件,运行环境等信息(eg:连接数据库的配置信息)
  2. 加载映射文件,即加载 sql 映射文件。该文件中配置了操作数据库的 sql 语句,需要在Mybatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表<mapper resource = "/xxxMapper.xml"/>
  3. 构造会话工厂:SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  4. 创建会话对象:sqlSession = sqlSessionFactory.openSession();
  5. Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护
  6. MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息
  7. 输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程
  8. 输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程

8. #{}和${}的区别

  1. #{}是占位符,有预编译处理,${}是拼接符,没有预编译处理
  2. Mybatis 在处理#{}时,#{}传入参数是以字符串传入,会将 sql 中的#{}替换为?号,调用PreparedStatement的set方法来赋值,在处理${}时,是将原值传入,就是把${}替换成变量的值,相当于JDBC中的Statement编译
  3. 变量替换后,#{}对应的变量会自动加上单引号,而${}对应的变量不会加上单引号
  4. #{} 可以有效的防止SQL注入,提高系统安全性;${} 不能防止SQL 注入

补充: 什么是 sql 注入?

用户提交带有恶意的数据与SQL语句进行字符串方式的拼接,从而影响了SQL语句的语义,最终产生数据泄露的现象


9. 模糊查询l语句该怎么写?

  1. %${name}%:这种方式可能会引起 sql 注入,不推荐使用
  2. %#{name}%注意:这里的#{}解析sql语句时,会在变量外侧自动加单引号'',所以这里%需要用双引号,否则无法查找到结果
  3. CONCAT('%',#{name},'%'):使用CONCAT()函数,推荐使用

10. 一级缓存和二级缓存的区别?

1. 一级缓存(本地缓存)

在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库

  • 一级缓存默认是开启的,我们不需要做任何配置
  • 指的是MybatisSqlSession对象的缓存
  • session关闭或者刷新的时候缓存清空
  • 不同sqlsession之间缓存互不影响

2. 二级缓冲(全局缓冲)

二级缓存指的就是同一个namespace下的mapper,二级缓存中,也有一个map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。

  • 二级缓冲默认是没有开启的,需要手动开启
  • 二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession
  • 可以认为它指的是MybatisSqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存

11. properties(属性)

properties可以对数据源的4个属性进行配置,有2种方式

1. 方式一

在properties标签内配置属性,在dataSource中获取属性值就可以了

在这里插入图片描述

2. 方式二

数据库的属性发生改变,我们需要修改配置文件。一般我们会把数据库的配置属性写在一个文件中,放在classpath下。

在这里插入图片描述
在这里插入图片描述

  • properties标签有2个属性,一个是resource,一个是url
  • 这里我们使用的是resource:是一个相对classpath下的路径,所有我们直接写jdbc.properties就可以了
  • 如果使用url的话,必须要满足url的要求才可以。url:uniform resource locator,统一资源定位符http:// localhost: 8080 /day01/servlet1/ ,分别对应 协议 主机名 端口号 URI,是web中可以唯一定位一个资源的路径
    在这里插入图片描述

12. typeAliases(别名)

在这里插入图片描述
这样的话,在sql映射文件中,就可以修改resultType,获取或者parameterType的值为user(大小写都可以)了

但是,这里又会发现一个问题,如果实体类比较多时,每一个类都需要设置别名,那么在配置文件中就会写很多的标签,会让配置文件体积变大,所以这里我们还可以通过另一个标签设置别名,只需指定需要设置别名的包即可

在这里插入图片描述
解决方案:

在这里插入图片描述


12. mappers(映射器)

mappers标签用于指定sql映射文件,这里有三种模式

1. 方式一

在这里插入图片描述

  • resource:使用相对于类路径的资源,指定sql映射文件的类路径

2. 方式二

在这里插入图片描述
3. 方式三

如果在我们的工程中,持久层接口和映射文件比较多的话,就要写很多的mapper,如下图:

在这里插入图片描述
所以,我们可以通过下面的方式去指定映射:

在这里插入图片描述
这种方式要求:持久层接口的名称和sql映射文件的文件名相同,并且路径相同


13. Mybatis的事务控制

1. Mybatis中事务的提交方式

在 JDBC 中我们可以通过手动方式将事务的提交改为手动方式,通过setAutoCommit()方法就可以调整,Mybatis 中事务的提交方式,本质上就是调用 JDBC 的 setAutoCommit()来实现事务控制

以保存用户为例:

在这里插入图片描述

在这里插入图片描述
执行完方法之后,需要执行再执行destroy方法:

在这里插入图片描述
在该方法中,手动提交事务。看一下执行过程:

在这里插入图片描述
这是Connection的整个变化过程,通过分析我们能够发现之前的 CUD 操作过程中,我们都要手动进行事务的提交,原因是 setAutoCommit()方法,在执行时它的值被设置为 false 了,所以我们在 CUD 操作中,必须通过sqlSession.commit()`方法来执行提交操作

2. Mybatis中自动提交事务

  • SqlSession中,openSession方法是重载的,之前我们使用factory.openSession()时,该方法会自动将autoCommit设置为false,即不会自动提交事务,我们必须自己手动提交事务

  • factory.openSession(boolean autoCommit):也可以使用该方法,将autoCommit设置为true,这样就会自动提交事务

在这里插入图片描述

修改代码如下

**加粗样式**
在这里插入图片描述
在这里插入图片描述
执行结果:

在这里插入图片描述

在这里插入图片描述
我们发现,此时事务就设置为自动提交了,同样可以实现CUD操作时记录的保存。虽然这也是一种方式,但就编程而言,设置为自动提交方式为 false 再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务情况来决定提交是否进行提交


14. Mybatis延迟加载策略

1. 什么是延迟加载

就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载

懒加载的优点:

先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快

懒加载的缺点:

因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:书香水墨 设计师:CSDN官方博客 返回首页

打赏作者

Surplus...

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值