Mybatis

文章目录

1. Mybatis缓存机制 ****

参考文献
在这里插入图片描述
作用:避免每次都去查db
一级缓存是SqlSession级别的缓存,也叫本地缓存。
跨SqlSession级别的,引入了二级缓存(全局缓存)。
先通过CachingExecutor查二级缓存

  • 对比一级缓存和二级缓存
    1)一级缓存 Mybatis的一级缓存是指SQLSession,一级缓存的作用域是SQlSession, Myabits默认开启一级缓存。
    在同一个SqlSession中,执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取。 当执行SQL时候两次查询中间发生了增删改的操作,则SQLSession的缓存会被清空。
    每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。 Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。 SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。
    2) Mybatis二级缓存是默认不开启的,作用于一个Application,是Mapper级别的,多个SqlSession使用同一个Mapper的sql能够使用二级缓存。

2. 动态SQL语句 ****

  • MyBatis 动态 SQL 可以让我们在 XML 映射文件内,以标签的形式编写动态 SQL,完成逻辑判断和动态拼接 SQL 的功能;
  • MyBatis 提供了 9 种动态 SQL标签:trim、where、set、foreach、if、choose、when、otherwise、bind
  • 执行原理:使用 OGNL 从 SQL 参数对象中计算表达式的值,根据表达式的值动态拼接 SQL,以此来完成动态 SQL 的功能。
    choose,when
    trim

3. 分页 ***

3. 1 几种分页方式

数组分页
SQL 分页
拦截器分页
RowBounds 分页

3.2 MyBatis 是如何进行分页的?

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

3.3 逻辑分页和物理分页

  • 物理分页
    物理分页就是数据库本身提供了分页方式,如MySQL的limit,oracle的rownum ,好处是效率高,不好的地方就是不同数据库有不同的搞法。
  • 逻辑分页
    逻辑分页利用游标分页,好处是所有数据库都统一,坏处就是效率低。
    **逻辑分页是一次性查询很多数据,然后再在结果中检索分页的数据。**这样做弊端是需要消耗大量的内存、有内存溢出的风险、对数据库压力较大。 物理分页是从数据库查询指定条数的数据,弥补了一次性全部查出的所有数据的种种缺点,比如需要大量的内存,对数据库查询压力较大等问题。

3.4 分页插件原理?如何编写一个插件?

  • MyBatis 仅可以编写针对 ParameterHandler 、 ResultSetHandler 、StatementHandler 、 Executor 这 4 种接口的插件,MyBatis 使用 JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler 的 invoke() 方法,当然,只会拦截那些你指定需要拦截的方法。
  • 实现 MyBatis 的 Interceptor 接口并复写 intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件

4. #{} 和 ${} 的区别是什么?

#{} 是预编译处理,${} 是字符串替换
Mybatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为 ? 号,调用 PreparedStatement 的 set 方法来赋值;使用 #{} 可以有效的防止 SQL 注入,提高系统安全性;
MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值。

5. MyBatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?

  • 第一种是使用 resultMap 标签,逐一定义列名和对象属性名之间的映射关系。
  • 第二种是使用 sql 列的别名功能,将列别名书写为对象属性名,比如 T_NAME AS NAME,对象属性名一般是name,小写,但是列名不区分大小写,MyBatis 会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成 T_NAME ASNaMe,MyBatis 一样可以正常工作。有了列名与属性名的映射关系后,MyBatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

6. Mybatis如何实现映射?

    1. XML映射文件:在MyBatis中,你可以为每个Java实体类创建一个对应的XML映射文件。这个文件描述了如何将SQL查询结果映射到Java对象,以及如何将Java对象参数映射到SQL查询中。
      映射文件通常包含以下几个部分:
      resultMap:定义了SQL查询结果如何映射到Java对象。你可以为每个字段指定一个别名,这个别名应该与Java实体类中的属性名称相匹配。sql:定义可重用的SQL片段。这可以让你在多个查询中重用相同的SQL代码,从而避免重复。
      select:定义查询操作。它包含SQL查询语句以及引用的resultMap或返回类型。
      insert、update、delete:定义插入、更新和删除操作。这些操作包含相应的SQL语句以及如何处理输入参数。
    1. 注解:MyBatis还允许你使用注解来定义映射。虽然注解相对于XML映射文件更简洁,但它们不适用于复杂的映射关系。
      以下是一些常用的MyBatis注解:
      @Select:用于定义查询操作。
      @Insert:用于定义插入操作。
      @Update:用于定义更新操作。
      @Delete:用于定义删除操作。
      @Results:定义了查询结果的映射关系。通常与@Result一起使用。
      @Result:定义单个字段的映射关系。
      @Param:用于将方法参数映射到SQL语句中。MyBatis在运行时会解析XML映射文件或注解,并将这些映射关系存储在内存中。当执行数据库操作时,MyBatis会根据这些映射关系来构建SQL语句并执行。
      此外,MyBatis还提供了一些高级功能,如动态SQL、一对一和一对多关联映射等,进一步简化了数据库操作。

7. Mybatis的架构原理及执行流程 ****

参考文献
在这里插入图片描述
在这里插入图片描述

8. namespace用法

namespace即空间命名名称,用于区分实现数据持久化的方式。namespace一般绑定对应的文件的全路径

参考文献

9. Executor执行器类型?如何指定 ****

  • SimpleExecutor:每执行一次 update 或 select 就开启一个 Statement 对象,用完立刻关闭Statement 对象
  • ReuseExecutor:执行 update 或 select,以 SQL 作为 key 查找 Statement对象,存在就使用,不存在就创建,用完后不关闭 Statement 对象,而是放置于 Map 内供下一次使用。简言之,就是重复使用Statement 对象
  • BatchExecutor:执行 update(没有 select,jdbc 批处理不支持 select),将所有 SQL都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个 Statement 对象,每个Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理,与 jdbc 批处理相同。 (mybatis如何实现批处理)
  • 指定类型的执行器
    在 MyBatis 配置文件中,可以指定默认的 ExecutorType 执行器类型,也可以手动给 DefaultSqlSessionFactory 的创建 SqlSession 的方法传递 ExecutorType 类型参数

10.Mybatis生成及调用mapper接口方法过程

MyBatis 会根据接口声明的方法信息,通过动态代理机制生成一个Mapper 实例,当调用接口方法时,根据这个方法的方法名和参数类型,确定Statement Id,底层还是通过 SqlSession.select/update( “statementId”, parameter) 等来实现对数据库的操作。
参考11题
可参考

11. Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗? ***

  • 原理
    最佳实践中,通常一个 xml 映射文件,都会写一个 Dao 接口与之对应。Dao 接口就是人们常说的 Mapper 接口,接口的全限名,就是映射文件中的 namespace 的值,接口的方法名,就是映射文件中 MappedStatement 的 id 值,接口方法内的参数,就是传递给 sql 的参数。
    Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MappedStatement ,举例: com.mybatis3.mappers. StudentDao.findStudentById ,可以唯一找到 namespace 为 com.mybatis3.mappers. StudentDao 下面 id = findStudentById 的 MappedStatement 。在 MyBatis 中,每一个 select 、insert 、update 、delete标签,都会被解析为一个 MappedStatement 对象。
  • 方法重载问题
    Dao 接口方法可以重载,但是需要满足以下条件:
    仅有一个无参方法和一个有参方法
    多个有参方法时,参数数量必须一致。且使用相同的 @Param ,或者使用 param1 这种

12. MyBatis 能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别

  • MyBatis 不仅可以执行一对一、一对多的关联查询,还可以执行多对一,多对多的关联查询,多对一查询,其实就是一对一查询,只需要把selectOne() 修改为 selectList() 即可;多对多查询,其实就是一对多查询,只需要把 selectOne() 修改为selectList() 即可。
  • 关联对象查询,有两种实现方式,一种是单独发送一个 sql去查询关联对象,赋给主对象,然后返回主对象。另一种是使用嵌套查询,嵌套查询的含义为使用 join 查询,一部分列是 A对象的属性值,另外一部分列是关联对象 B 的属性值,好处是只发一个 sql 查询,就可以把主对象和其关联对象查出来。

13. MyBatis 执行批量插入,能返回数据库主键列表吗?

Mybatis返回主键列表的资料
1、升级Mybatis版本到3.3.1。官方在这个版本中加入了批量新增返回主键id的功能
2、在Dao中不能使用@param注解。
3、Mapper.xml中使用list变量(parameterType=“java.util.List”)接受Dao中的参数集合。

<!-- 批量新增 --> 
<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id" > 
    INSERT INTO 
        <include refid="t_shop_resource" /> 
    (relation_id, summary_id, relation_type) 
    VALUES 
        <foreach collection="list" index="index" item="shopResource" separator=","> 
        ( 
        #{shopResource.relationId}, #{shopResource.summaryId}, #{shopResource.relationType} 
        ) 
        </foreach> 
</insert>
  • 对于单条插入

1、对于支持生成自增主键的数据库:增加 useGenerateKeys和keyProperty ,insert标签属性。
2、不支持生成自增主键的数据库:使用。

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

MyBatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在 MyBatis 配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。
使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 a.getB().getName() ,拦截器 invoke() 方法发现 a.getB() 是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 a.getB().getName() 方法的调用。这就是延迟加载的基本原理。

15. MyBatis 的 xml 映射文件中,不同的 xml 映射文件,id 是否可以重复?

不同的 xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配置 namespace,那么 id 不能重复;毕竟 namespace 不是必须的,只是最佳实践而已。(看是否配置了namespace)
原因就是 namespace+id 是作为 Map<String, MappedStatement> 的 key 使用的,如果没有 namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。

16. MyBatis 是否可以映射 Enum 枚举类?

MyBatis 可以映射枚举类,不单可以映射枚举类,MyBatis 可以映射任何对象到表的一列上。映射方式为自定义一个 TypeHandler ,实现 TypeHandler 的 setParameter() 和 getResult() 接口方法。 TypeHandler 有两个作用:
一是完成从 javaType 至 jdbcType 的转换;
二是完成 jdbcType 至 javaType 的转换,体现为 setParameter() 和 getResult() 两个方法,分别代表设置 sql 问号占位符参数和获取列查询结果

17. MyBatis 映射文件中,如果 A 标签通过 include 引用了 B 标签的内容,请问,B 标签能否定义在 A 标签的后面,还是说必须定义在 A 标签的前面?

虽然 MyBatis 解析 xml 映射文件是按照顺序解析的,但是,被引用的 B 标签依然可以定义在任何地方,MyBatis 都可以正确识别。
原理是,MyBatis 解析 A 标签,发现 A 标签引用了 B 标签,但是 B 标签尚未解析到,尚不存在,此时,MyBatis 会将 A 标签标记为未解析状态,然后继续解析余下的标签,包含 B 标签,待所有标签解析完毕,MyBatis 会重新解析那些被标记为未解析的标签,此时再解析 A 标签时,B 标签已经存在,A 标签也就可以正常解析完成了。

18. 简述 MyBatis 的 xml 映射文件和 MyBatis 内部数据结构之间的映射关系?

MyBatis 将所有 xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。
在 xml 映射文件中, parameterMap 标签会被解析为 ParameterMap 对象,其每个子元素会被解析为 ParameterMapping 对象。
resultMap 标签会被解析为 ResultMap 对象,其每个子元素会被解析为 ResultMapping 对象。
每一个 select、insert、update、delete 标签均会被解析为 MappedStatement 对象,标签内的 sql 会被解析为 BoundSql 对象。

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

Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而 MyBatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具。

20. Mybatis与Mybatis-plus对比

参考
mybatis

所有SQL语句全部自己写
手动解析实体关系映射转换为MyBatis内部对象注入容器
不支持Lambda形式调用

mybatis-plus

强大的条件构造器,满足各类使用需求
内置的Mapper,通用的Service,少量配置即可实现单表大部分CRUD操作
支持Lambda形式调用
提供了基本的CRUD功能,连SQL语句都不需要编写
自动解析实体关系映射转换为MyBatis内部对象注入容器
mybatis-plus补充
  • @TableField(exist = false) 注解
    可以解决表中表的问题,加载bean属性上,表示当前属性不是数据库的字段,但在项目中必须使用,这样可以用来把一个数据表当作一个字段来输出,用来实现表中表数据输出。这样设置在新增等使用bean的时候,mybatis-plus就会忽略这个,不会报错

21. Mybatis的设计模式

添加链接描述
添加链接描述

  • 单例模式
    单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
    在Mybatis中有两个地方用到单例模式,ErrorContext和LogFactory,其中ErrorContext是用在每个线程范围内的单例,用于记录该线程的执行环境错误信息,而LogFactory则是提供给整个Mybatis使用的日志工厂,用于获得针对项目配置好的日志对象。
  • 工厂模式
    在Mybatis中以 Factory 结尾的类,基本上都是使用了工厂模式。
    SqlSessionFactory:创建 SqlSession 对象。
    ObjectFactory:对象工厂,所有对象都要由工厂来产生 。
    MapperProxyFactory:创建映射器代理 MapperProxy 对象。
  • 模板方法模式
    在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
    在 Mybatis 中,例如父类 BaseExecutor,子类 SimpleExecutor、BatchExecutor、ReuseExecutor。还有 BaseTypeHandler 和所有的子类例如 IntegerTypeHandler
  • 代理模式
    Mybatis 实现的核心,比如 MapperProxy 为绑定我们开发的 Mapper 和 Mapper.xml 创建代理类、Plugin 为每个插件创建一个代理类等。
  • 装饰器模式
    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。
    在 Mybatis 中,Cache 的实现类 LruCache、FifoCache 等都是装饰一个类 PerpetualCache。
  • 责任链模式
    请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。
    在 Mybatis 中,InterceptorChain 中有个属性 interceptors,其中就是保存了所有 Mybatis 的插件,执行插件的时候就是遍历这个 interceptors。A 插件->B 插件->C 插件…
  • 适配器模式
    将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)
    Log接口定义了Mybatis直接使用的日志方法,而Log接口具体由谁来实现呢?Mybatis提供了多种日志框架的实现,这些实现都匹配这个Log接口所定义的接口方法,最终实现了所有外部日志框架到Mybatis日志包的适配
  • 建造者模式
    建造者模式使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
    在 Mybatis 中有 SqlSessionFactoryBuilder,构建 SqlSessionFactory, 这就是使用了建造者模式。
    另外在 Mybatis 中类名以 Builder 结尾基本上都是建造者模式。

22. Mybatis与JDBC对比

添加链接描述
添加链接描述

  • JDBC的缺点
    (1)需要频繁的创建数据库连接
    (2)涉及到的增删改查等功能需要在各个java文件中编写大量代码
    (3)对于底层事务、数据类型转换等都需要手动处理,又是各种代码
  • Mybatis优点
    (1)封装了jdbc对数据库的各种操作,减少代码
    (2)增加了连接池、一、二级缓存
    (3)可以自动生成sql语句

23. JDBC连接数据库的步骤

添加链接描述

  • 提供四个参数:用户名,密码,url,驱动
  • 加载JDBC数据库驱动
  • 创建数据库的连接
  • 创建statement连接
  • 执行sql语句
  • 遍历结果集
  • 处理异常,关闭连接
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值