mybatis知识点总结

参考JavaGuide面试突击里面的mybatis部分

目录

1、mybatis原理 / 核心流程

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

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

4、Mybatis 能执行⼀对⼀、⼀对多的关联查询吗?都有哪些实现方式,以及它们之间的区别。

5、mybatis延迟加载怎么做的?原理是什么?

6、Mybatis 都有哪些 Executor 执行器?它们之间的区别是什么?

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

8、mybatis的一级缓存和二级缓存


1、mybatis原理 / 核心流程

  1. mybatis应用程序通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件中构建出SqlSessionFactory。
  2. 然后,SqlSessionFactory的实例直接开启一个SqlSession。
  3. 再通过SqlSession实例获得Mapper对象并运行Mapper映射的SQL语句,完成对数据库的CRUD和事务提交,之后关闭SqlSession。

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

        ①接口的全限名,就是映射文件中的 namespace的值。接口的方法名,就是映射文件中 MappedStatement 的 id 值。在 Mybatis中,每⼀个 <select> 、 <insert> 、 <update> 、 <delete> 标签,都会被解析为⼀个 MappedStatement 对象。当调用接口方法时,接⼝全限名+⽅法名拼接字符串作为 key 值,可唯⼀定位⼀个 MappedStatement。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.mmall.dao.OrderMapper" >

  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from mmall_order
    where id = #{id,jdbcType=INTEGER}
  </delete>

        ②不能重载的,因为是全限名+方法名的保存和寻找策略。
Dao 接口的工作原理是 JDK 动态代理,Mybatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象,代理对象 proxy 会拦截接口方法,转而执行 MappedStatement 所代表的 sql,然后将 sql 执行结果返回。

Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件,id 是否可以重复?

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

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

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

如果resultType直接写一个pojo类,不按第一种第二种那样设置。就必须开启mybatis设置里的驼峰命名规则,否则匹配不上。

4、Mybatis 能执行⼀对⼀、⼀对多的关联查询吗?都有哪些实现方式,以及它们之间的区别。

一对一:比如订单表关联用户表,查出哪个订单的信息及对应用户。

//sql
<!-- 查询订单,同时包含用户数据 -->
<select id="queryOrderUser" resultType="orderUser">
	SELECT
	o.id,
	o.user_id
	userId,
	o.number,
	o.createtime,
	o.note,
	u.username,
	u.address
	FROM
	`order` o
	LEFT JOIN `user` u ON o.user_id = u.id
</select>

这种情况下我们需要定义出来一个pojo作为返回的resulttype。

一对多:比如用户表关联订单表,查出哪个用户的信息及对应用户的一些订单。

xml:

<resultMap type="user" id="userOrderResultMap">
	<id property="id" column="id" />
	<result property="username" column="username" />
	<result property="birthday" column="birthday" />
	<result property="sex" column="sex" />
	<result property="address" column="address" />
 
	<!-- 配置一对多的关系 -->
	<collection property="orders" javaType="list" ofType="order">
		<!-- 配置主键,是关联Order的唯一标识 -->
		<id property="id" column="oid" />
		<result property="number" column="number" />
		<result property="createtime" column="createtime" />
		<result property="note" column="note" />
	</collection>
</resultMap>
 
<!-- 一对多关联,查询订单同时查询该用户下的订单 -->
<select id="queryUserOrder" resultMap="userOrderResultMap">
	SELECT
	u.id,
	u.username,
	u.birthday,
	u.sex,
	u.address,
	o.id oid,
	o.number,
	o.createtime,
	o.note
	FROM
	`user` u
	LEFT JOIN `order` o ON u.id = o.user_id
</select>

这种我们也要定义一个pojo来接收返回对象,是一个包含用户相关字段以及一个List<Order>字段的类。

同时用resultMap配置好对应字段的关系,把一对多的订单信息配置在collection里。

5、mybatis延迟加载怎么做的?原理是什么?

        如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。 所以延迟加载即先从单表查询、需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

        原理:

        Mybatis 仅支持 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() 方法的调用。这就是延迟加载的基本原理。

6、Mybatis 都有哪些 Executor 执行器?它们之间的区别是什么?

Mybatis 有三种基本的 Executor 执行器, SimpleExecutor 、 ReuseExecutor 、 BatchExecutor 。可以在配置文件中指定。
SimpleExecutor :每执行⼀次 update 或 select,就开启⼀个 Statement 对象,用完立刻关闭
Statement 对象。
ReuseExecutor :执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,⽽是放置于 Map<String, Statement>内,供下⼀次使用。简言之,就是重复使用 Statement 对象。
BatchExecutor :执行 update(没有 select,JDBC 批处理不支持 select),将所有 sql 都添加到批处理中(addBatch()),等待统⼀执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐⼀行 executeBatch()批处理。与JDBC 批处理相同。

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

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

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

8、mybatis的一级缓存和二级缓存

  • 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
  • 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的。

缓存的执行原理和前面提到的一级缓存是差不多的,二级缓存与一级缓存区别在于二级缓存的范围更大,多个sqlSession可以共享一个mapper中的二级缓存区域。mybatis是如何区分不同mapper的二级缓存区域呢?它是按照不同mapper有不同的namespace来区分的,也就是说,如果两个mapper的namespace相同,即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域中。

 【MyBatis学习13】MyBatis中的二级缓存_武哥聊编程-CSDN博客_mybatis二级缓存

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值