【MyBatis】MyBatis问题整理(绝对的干货)

接口绑定实现方式

  • 通 过 注 解 绑 定 , 就 是 在 接 口 的 方 法 上 面 加 上 @Select 、@Update 等 注 解 , 里 面 包 含 Sql 语句来绑定;

  • 通 过 xml 里 面 写 SQL 来 绑 定 , 在 这 种 情 况 下 , 要 指 定 xml 映 射 文 件 里 面 的 namespace

必 须为接口的全路径 名。当 Sql 语句比较简单时 候 ,用注解绑定, 当 SQL 语 句比 较复杂时 候,用 xml 绑定,一般用 xml 绑定的比较多。

使用 MyBatis 的 mapper 接口调用时有 哪些要求 ?

1、Mapper 接口 方法名和 mapper.xml 中定 义的 每个 sql 的 id 相同 。

2、Mapper 接 口方 法 的输入参 数类型 和 mapper.xml 中 定义的 每个 sql 的 parameterType 的类型相同。

3、Mapper 接口方 法 的输 出 参 数类型 和 mapper.xml中定义 的 每个 sql 的 resultType 的类 型相同。

4、Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径。

通 常 一 个 Xml 映 射 文 件 , 都 会 写 一 个 Dao 接 口 与 之 对 应 , 请 问 , 这 个 Dao 接口的工作原理是 什么?Dao 接口里的方法,参 数不同时,方法能 重载吗

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 接口方法的重载

Dao 接口 里的方法,是不能重载的,因为 是全限名+方法名的保存 和寻找策略。

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 自然 也就 不同。

简述 Mybatis 的 Xml 映射文件和 Mybatis 内部数据结构之间的映射关系?

答 :Mybatis 将 所有 Xml 配 置 信息 都 封 装 到 All-In-One 重 量 级对象 Configuration 内 部 。

在 Xml 映 射 文 件 中 ,< parameterMap >标 签 会 被 解 析 ParameterMap 对象 , 其每个子元素会被解析为 ParameterMapping 对 象。<resultMap> 标签会被解析为 ResultMap 对象 , 其每个子元素会被解析为 ResultMapping 对 象 。 每 一 个<select><insert><update><delete>标 签 均会被 解 析为 MappedStatement 对 象 ,标签 内的 sql 会 被 解 析为 BoundSql 对象 。

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

  • 第一种是使用 标签,逐一定 义列 名和对象 属性名之间的映射 关系。

  • 第 二种是使用 sql 列的别名功 能 ,将列别名 书写为对 象 属性名,比 如 T_NAME AS NAME ,

对 象属性名一 般是 name ,小写,但 是列名不 区 分大小写,Mybatis 会 忽略列名大 小写,智能 找 到 与 之 对 应 对 象 属 性 名 ,你 甚 至 可 以 写 成 T_NAME AS NaMe ,Mybatis 一 样 可 以 正 常工作。

有 了列名与属性名的 映射关系后,Mybatis 通 过反 射创建对 象,同时使用反 射给对象的属性 逐一赋值并返回, 那些找不到映射关 系的属性,是无法 完成赋值的。

Xml 映射 文件 中,除了 常见的 select|insert|updae|delete 标签之外,还有哪 些标签?

还 有 很 多 其 他 的 标 签 , 、 、 、 、 ,加上动态 sql的 9个标签 ,
trimwhere set|foreach if choose when otherwise bind 等 ,其中<sql> 为 sql 片 段 标 签 ,通过< include> 标签引入 sql 片段, 为不支持自增 的主 键生成策 略标签。

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

虽 然 Mybatis 解 析 Xml 映射文件是 按照顺 序解析的,但 是,被引用的 B 标 签依 然可以定义 在任何地方,Mybatis 都可 以正 确识别。

原 理是,Mybatis 解 析 A 标 签,发现 A 标 签引 用了 B 标签,但是 B 标 签尚未解析到,尚 不存 在 , 此 时 , Mybatis 会 将 A 标 签 标 记 为 未 解 析 状 态 , 然 后 继 续 解 析 余 下的 标 签 , 包含 B标 签,待所有标签解析 完毕 ,Mybatis 会重新解析那些 被标记为未解析的 标 签 ,此 时再 解 析 A 标签时, B 标签 已经 存在,A 标签 也就可以 正常解析完成了。

高级查询

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

有 联 合 查 询 和 嵌 套 查 询 。 联 合 查 询 是 几 个 表 联 合 查 询 , 只 查 询一 次, 通 过 在 resultMap 里 面的 associationcollection 节点 配置一对一,一对 多的类就可以完成。

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

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

Mybatis 可 以 映 射 枚 举 类 , 不 单 可 以 映 射 枚 举 类 , Mybatis 可 以 映 射 任 何 对 象 到 表 的 一 列上 。 映 射 方 式 为 自 定 义 一 个 TypeHandler , 实 现 TypeHandler 的 setParameter() 和 getResult() 接口 方法 。

TypeHandler 有 两个作 用,一是完 成 从 javaType 至 jdbcType 的 转换 ,二是完成 jdbcType 至 javaType 的 转 换 , 体 现 为 setParameter() 和 getResult() 两 个 方 法 , 分 别 代 表 设 置 sql 问号占位符参数和 获取列查询结果。

动态 SQL

Mybatis 动态 sql 是做 什么的?都有哪些 动态 sql ?能简述一下动态 sql 的执 行原理不?

Mybatis 动 态 sql 可以让我们在 Xml 映射文 件内,以 标签 的形式 编写动 态 sql,完成逻辑判断 和 动 态 拼 接 sql 的 功 能 , Mybatis提 供 了 9 种 动 态 sql 标 签 trim where set foreach if choose when otherwise bind

其 执 行 原 理 为 , 使 用 OGNL 从 sql 参数 对 象 中 计 算 表 达 式的 值, 根 据 表 达 式 的 值 动 态 拼 接 sql ,以 此来完成动态 sql 的功能。

插件模块

Mybatis 是如 何进行分 页的 ?分页插 件的原理是什么?

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

分 页 插 件 的 基 本 原 理 是 使 用 Mybatis 提 供 的 插 件接 口 , 实 现 自 定 义 插 件 , 在 插 件的 拦截 方法 内拦截待执 行的 sql ,然 后重 写 sql ,根 据 dialect 方言,添 加对应的 物 理分页语句 和物理 分页参数。

举 例

select * from student ,拦 截 sql 后 重 写 为 :

select t.* from (select * from student) t limit 0, 10

简述 Mybatis 的插件运 行原 理,以及 如何编写一个插件 。

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

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

缓存

Mybatis 的一 级、二级 缓存

1)一 级缓存 : 基于 PerpetualCache 的 HashMap 本地缓 存 ,其 存储 作 用域为 Session,当 Session flush 或 close 之 后 , 该 Session 中 的 所 有 Cache 就 将 清 空 , 默 认 打 开 一 级缓存。

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

3) 对 于 缓 存 数 据 更 新 机 制 , 当 某 一 个 作 用 域 ( 一 级 缓 存 Session/ 二 级 缓 存 Namespaces) 的进行了 C/U/D 操作 后,默认 该作用域下所有 select 中的 缓存将被 clear。

猜你喜欢

转载自blog.csdn.net/Black_Customer/article/details/107420116