MyBatis
2022-11-29 14:00:57 25 举报
AI智能生成
根据 JavaGuide 绘制的脑图
作者其他创作
大纲/内容
什么是 MyBatis?
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,加载驱动、创建连接、创建 statement <br>等繁杂的过程,开发者开发时只需要关注如何编写 SQL 语句,可以严格控制 sql 执行性能,灵活度高。</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">作为一个半 ORM 框架,MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO <br>映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">通过 xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中 sql 的动态参数进行映射<br>生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。(从执行 sql 到返回 result 的过程)</span>
Mybaits的优缺点?
优点
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">基于 SQL 语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL 写在 XML 里,<br>解除 sql 与程序代码的耦合,便于统一管理;提供 XML 标签,支持编写动态 SQL 语句,并可重用。</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">与 JDBC 相比,减少了 50% 以上的代码量,消除了 JDBC 大量冗余的代码,不需要手动开关连接;</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">很好的与各种数据库兼容(因为 MyBatis 使用 JDBC 来连接数据库,所以只要 JDBC 支持的数据库 MyBatis 都支持)。</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">能够与 Spring 很好的集成;</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象关系映射标签,支持对象关系组件维护。</span>
缺点
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">SQL 语句的编写工作量较大,尤其当字段多、关联表多时;</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">SQL 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。</span>
#{} 和 ${} 的区别是什么?<br>
关于 #{}
#{} 是 SQL 的参数占位符,Mybatis 会将 SQL 中的 #{} 替换为 ? 号,在 SQL 执行前会使用 PreparedStatement <br>的参数设置方法,按序给 SQL 的 ? 号占位符设置参数值,如 ps.setInt(0, parameterValue) 。
<span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">所以,</span><code style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; word-break: break-word; padding: 0.2em 0.4em; margin: 0px; border-radius: 3px;">#{}</code><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;"> 是 </span><span style="box-sizing: border-box; font-weight: bolder; font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;"><font color="#0000ff">预编译处理</font></span><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">,它可以有效防止 SQL 注入,提高系统安全性,推荐使用。</span>
#{item.name} 的取值方式为使用 <b><font color="#0000ff">反射从参数对象中 </font></b>获取 item 对象的 name 属性值,相当于 param.getItem().getName()。
关于 ${}
${} 常见于相关配置文件中,常被用于 XML 标签属性值以及 SQL 内部,用来做 <b><font color="#0000ff">字符串替换</font></b>。<br>例如将 ${driver} 会被静态替换为 com.mysql.jdbc.Driver :
<span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">另外,</span><code style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; word-break: break-word; padding: 0.2em 0.4em; margin: 0px; border-radius: 3px;">${}</code><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;"> 也可以对传递进来的参数 </span><span style="box-sizing: border-box; font-weight: bolder; font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">原样拼接 </span><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">在 SQL 中。</span><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">代码如下:</span><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;"><br></span><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">(注意:生产环境下,不推荐这么做。会带来 SQL 注入的风险。)</span>
${} 的主要应用场景:<br><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">在使用类似 Sharding-JDBC 等分库分表中间件时会用到,比如说,有张用户表 </span><code style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; word-break: break-word; padding: 0.2em 0.4em; margin: 0px; border-radius: 3px;">t_user</code><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">, 考虑到未来用户数据<br>的增长,以及查询的效率(使每张表数据量保持在 500w 之内),设计时根据 user_id 分了 8 张表, 如下所示:</span><br>
<span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">这时,在代码逻辑层就需要根据 user_id 动态指定表名,也就是说,对表名路由时,<br>需要对 </span><code style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; word-break: break-word; padding: 0.2em 0.4em; margin: 0px; border-radius: 3px;">user_id % 8</code><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">处理后,才能得到记录具体落到哪张表:</span>
<span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;">算出表名后,再动态设置表名:</span>
Mybatis的 Xml 映射文件中,不同的 Xml 映射文件,id 是否可以重复?
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;"><b><font color="#0000ff">不同的 Xml 映射文件</font></b>,如果配置了 namespace,那么 id 可以重复;如果没有配置 namespace,那么 id 不能重复;</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">原因就是 namespace+id 是作为 Map 的 key 使用的,如果没有 namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。<br>有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">备注:在旧版本的 Mybatis 中,namespace 是可选的,不过新版本的 namespace <br>已经是必须的了。所以在不同的 xml 映射文件, id 可以重复。</span>
xml 映射文件中,除了常见的 select、insert、update、delete 标签之外,还有哪些标签?<br>
还有很多其他的标签, <resultMap> 、 <parameterMap> 、 <sql> 、 <include> 、 <selectKey> ;<br>动态 SQL 的 9 个标签:trim|where|set|foreach|if|choose|when|otherwise|bind 等,<br>其中 <sql> 为 sql 片段标签,通过 <include> 标签引入 sql 片段, <selectKey> 为不支持自增的主键生成策略标签。<br>
Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?<br>
<span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;">最佳实践中,通常一个 xml 映射文件,都会写一个 Dao 接口与之对应。Dao 接口就是人们常说的 </span><code style="font-family: var(--font-family-code); padding: 0.25rem 0.5rem; border-radius: 3px; background: rgba(127, 127, 127, 0.12); overflow-wrap: break-word; transition: background-color var(--color-transition),color var(--color-transition); margin: 0px; text-align: justify;">Mapper</code><span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;"> 接口,接口的全限名,就是映射<br>文件中的 namespace 的值,接口的方法名,就是映射文件中 </span><code style="font-family: var(--font-family-code); padding: 0.25rem 0.5rem; border-radius: 3px; background: rgba(127, 127, 127, 0.12); overflow-wrap: break-word; transition: background-color var(--color-transition),color var(--color-transition); margin: 0px; text-align: justify;">MappedStatement</code><span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;"> 的 id 值,接口方法内的参数,就是传递给 sql 的参数。</span>
Mapper 接口是没有实现类的,当调用接口方法时,<b><font color="#0000ff">接口全限名+方法名 </font></b>拼接字符串作为 key 值,<br>可唯一定位一个 MappedStatement ,举例:com.mybatis3.mappers.StudentDao.findStudentById ,<br>可以唯一找到 namespace 为 com.mybatis3.mappers. StudentDao 下面 id = findStudentById 的 MappedStatement 。<br>在 MyBatis 中,每一个 <select> 、 <insert> 、 <update> 、 <delete> 标签,都会被解析为一个 MappedStatement 对象。
<span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;">Dao 接口里的方法可以重载</span>
<span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;">Mybatis 版本 3.3.0,亲测如下:</span>
<span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;">然后在 </span><code style="font-family: var(--font-family-code); padding: 0.25rem 0.5rem; border-radius: 3px; background: rgba(127, 127, 127, 0.12); overflow-wrap: break-word; transition: background-color var(--color-transition),color var(--color-transition); margin: 0px; text-align: justify;">StuMapper.xml</code><span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;"> 中利用 Mybatis 的动态 sql 就可以实现。</span>
<span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;">能正常运行,并能得到相应的结果,这样就实现了在 Dao 接口中写重载方法。</span>
Mybatis 的 Dao 接口可以有多个重载方法,但是 <b><font color="#0000ff">多个接口对应的映射必须只有一个</font>,否则启动会报错。</b>
<span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;">Dao 接口的工作原理是 JDK 动态代理,MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象,<br>代理对象 proxy 会拦截接口方法,转而执行 </span><code style="font-family: var(--font-family-code); padding: 0.25rem 0.5rem; border-radius: 3px; background: rgba(127, 127, 127, 0.12); overflow-wrap: break-word; transition: background-color var(--color-transition),color var(--color-transition); margin: 0px; text-align: justify;">MappedStatement</code><span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;"> 所代表的 sql,然后将 sql 执行结果返回。</span>
MyBatis 动态 sql 是做什么的?都有哪些动态 sql?<br>
<span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;">MyBatis 动态 sql 可以让我们在 xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能。</span>
<span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;">其执行原理为:使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql,以此来完成动态 sql 的功能。</span>
MyBatis 提供了 9 种动态 sql 标签:<br><ul><li><if></if></li><li><where></where>(trim,set)</li><li><choose></choose>(when, otherwise)</li><li><foreach></foreach></li><li><bind/></li></ul>
if
用法:
子主题
choose、when、otherwise
用法:
解析:
foreach
用法,<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">譬如我们传入一个 List 列表查询 id 在 1 ~ 100 的用户记录:</span>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">最终拼接完整的语句就变成:</span>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">所以经过上面的举栗,也基本能猜出 foreach 标签元素的基本用法:<br></span><ul style="box-sizing: border-box; padding-left: 2rem; margin-bottom: 1.25rem; font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";"><li style="box-sizing: border-box;">foreach 标签:顶层的遍历标签,单独使用无意义</li><li style="box-sizing: border-box;">collection 属性:必填,Map 或者数组或者列表的属性名(不同类型的值获取下面会讲解)</li><li style="box-sizing: border-box;">item 属性:变量名,值为遍历的每一个值(可以是对象或基础类型),如果是对象那么<br>依旧是使用 OGNL 表达式取值即可,例如 #{item.id} 、#{ user.name } 等</li><li style="box-sizing: border-box;">index 属性:索引的属性名,在遍历列表或数组时为当前索引值,当迭代的对象时 Map 类型时,该值为 Map 的键值(key)</li><li style="box-sizing: border-box;">open 属性:循环内容开头拼接的字符串,可以是空字符串</li><li style="box-sizing: border-box;">close 属性:循环内容结尾拼接的字符串,可以是空字符串</li><li style="box-sizing: border-box;">separator 属性:每次循环的分隔符</li></ul>
所以上面的示例也可以写成:
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">最终拼接完整的语句就变成:<br>(</span><span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">在数据量大的情况下这个性能会比较尴尬,这里仅仅做一个用法的举例。)</span>
注意:传入 List 或 数组时,系统会默认添加一个 “key”为 List 或 数组 的值,把内容放入这个 key 对应的集合中。<br>但是,当传入的参数为 <b>Map</b> 对象时,系统并 <b>不会</b> 默认添加一个 key 值,需要手工传入。<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">例如:传入 key 值为 map2 <br>的集合对象,在 foreach 标签中可以直接通过 collection="map2" 获取到 Map 对象。</span>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">挺闹心,map1 套着 map2,才能在 foreach 的 collection 属性中获取到。</span>
每次都要这么麻烦?要嵌套 map 才行?
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">在 Mybatis 框架中,所有传入的任何参数都会供上下文使用,于是 <b><font color="#0000ff">参数会被统一放到一个内置参数池子 </font></b>里面,<br>这个内置参数池子的数据结构是一个 map 集合,而这个 map 集合可以通过使用 “_parameter” 来获取,<br>所有 key 都会存储在 _parameter 集合中,因此:<br><br></span><ul style="box-sizing: border-box; padding-left: 2rem; margin-bottom: 1.25rem; font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";"><li style="box-sizing: border-box;">当你传入的参数是一个 list 类型时,那么这个参数池子需要有一个 key 值,以供上下文获取这个 list 类型的对象,<br>所以默认设置了一个 'list' 字符串作为 key 值,获取时通过使用 _parameter.list 来获取,一般使用 list 即可。</li><li style="box-sizing: border-box;">同样的,当你传入的参数是一个 array 数组时,那么这个参数池子也会默认设置了一个 'array' 字符串作为 key 值,<br>以供上下文获取这个 array 数组的对象值,获取时通过使用 _parameter.array 来获取,一般使用 array 即可。</li><li style="box-sizing: border-box;">但是!当你传入的参数是一个 map 集合类型时,那么这个参数池就没必要为你添加默认 key 值了,因为 map 集合类型本身就会有很多 key 值,<br>例如你想获取 map 参数的某个 key 值,你可以直接使用 _parameter.name 或者 _parameter.age 即可,就没必要还用 _parameter.map.name 或<br>_parameter.map.age,所以这就是 map 参数类型无需再构建一个 'map' 字符串作为 key 的原因,对象类型也是如此,例如你传入一个 User 对象。</li></ul>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">因此,如果是 Map 集合,你可以这么使用:</span>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">直接使用 collection="_parameter",会发现神奇的 key 和 value 都能通过 _parameter 遍历在 index 与 item 之中。</span>
where、set、trim
where 和 set 都继承了 trim 标签:
where
where 用法:
解析:<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">若子句的开头为 “AND” 或 “OR”,where 标签也会将它替换去除。</span><span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">如果 age 传入有效值 10 ,<br>满足 age != null 的条件之后,那么就会返回 where 标签并去除首个子句运算符 and,最终的 SQL 语句会变成:</span><span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";"><br></span>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">值得注意的是,where 标签 </span><span style="box-sizing: border-box; font-weight: bolder; font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">只会</span><span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";"> 智能的去除(忽略)首个满足条件语句的前缀,所以就建议在使用 where 标签的时候,<br>每个语句都最好写上 and 前缀或者 or 前缀,否则若第 2,3 .... 个 <if> 都满足条件时,就没有连接符了。</span>
set
set 用法:
解析:<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">set 标签会智能拼接更新字段,以上例子如果传入 age =10 和 username = '潘潘' ,则有两个字段满足更新条件,于是 set 标签会智能拼接<br>" age = 10 ," 和 "username = '潘潘' ," 。其中由于后一个 username 属于最后一个子句,所以末尾逗号会被智能去除,最终的 SQL 语句是:</span>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">另外需要注意,set 标签下需要保证至少有一个条件满足,否则依然会产生语法错误,<br>例如在无子句条件满足的场景下,最终的 SQL 语句会是这样:</span>update user ;
trim
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">上面我们介绍了 where 标签与 set 标签,它俩的共同点无非就是前置关键词 where 或 set 的插入,<br>以及前后缀符号(例如 AND | OR | ,)的智能去除。</span>
其实 where 标签和 set 标签都只是 trim 标签的某种实现方案,trim 标签底层是通过 TrimSqlNode 类来实现的,它有几个关键属性:<br><br><ul><li>prefix :前缀,当 trim 元素内存在内容时,会给内容插入指定前缀;</li><li>suffix :后缀,当 trim 元素内存在内容时,会给内容插入指定后缀;</li><li>prefixesToOverride :前缀去除,支持多个,当 trim 元素内存在内容时,会把内容中匹配的前缀字符串去除;</li><li>suffixesToOverride :后缀去除,支持多个,当 trim 元素内存在内容时,会把内容中匹配的后缀字符串去除;</li></ul>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">所以 where 标签如果通过 trim 标签实现的话可以这么编写:</span>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">而 set 标签如果通过 trim 标签实现的话可以这么编写:</span>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">所以可见 trim 是足够灵活的,不过由于 where 标签和 set 标签这两种 trim 标签变种<br>方案已经足以满足我们实际开发需求,所以直接使用 trim 标签的场景实际上不太很多</span>
bind
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">这个标签就是可以创建一个变量,并绑定到上下文,即供上下文使用。</span>
用法:
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">上面例子的功效,其实就是辅助构建模糊查询的语句拼接,为啥不直接拼接语句就行了,为什么还要搞出一个变量,绕一圈呢?</span>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">平时我们使用 mysql 都是如何拼接模糊查询 like 语句的?</span>
但是,万一有一天换数据库了,那么上述模糊查询的 like 语句可能不通用,则需要进行修改。
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">所以才有了一开始我们介绍 bind 标签官网的这个例子,无论使用哪种数据库,这个模糊查询的 Like 语法都是支持的:</span>
<span style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";">这个 bind 的用法,解决了数据库重新选型后导致的一些问题,在实际工作中发生的概率不会太大,所以 bind 确实也使用的不多</span>
MyBatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?<br>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">第一种是使用 resultMap 标签,逐一定义数据库列名和对象属性名之间的映射关系。</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">第二种是使用sql列的别名功能,将列的别名书写为对象属性名。</span><span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", STHeiti, "Microsoft YaHei", SimSun, sans-serif; text-align: justify;">比如 T_NAME AS NAME,对象属性名一般是 name,<br>小写,但是列名不区分大小写,MyBatis 会忽略列名大小写,智能找到与之对应对象属性名</span><span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;"><br></span><span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;"><br>有了列名与属性名的映射关系后,Mybatis 通过反射创建对象,<br>同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。</span>
使用 MyBatis 的 mapper 接口调用时有哪些要求?
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">Mapper 接口方法名和 mapper.xml 中定义的每个 sql 的 id 相同;</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同;</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同;</span><br style="box-sizing: border-box; margin: 0px; padding: 0px; display: block; font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">Mapper.xml 文件中的 namespace 是 mapper 接口的类路径。</span>
在 mapper 中如何传递多个参数?
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">第一种:使用 #{参数编号} 获取</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">第二种: 使用 @param 注解</span>
<span style="font-family: -apple-system, HuaweiSans, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "Microsoft JhengHei", SimSun, sans-serif;">第三种:多个参数封装成 map</span>
一对一、多对一、一对多的关联查询
一对一/多对一关联查询
在 MyBatis 中,通过 <b><font color="#0000ff"><resultMap></font></b> 元素的子元素 <b><font color="#0000ff"><association></font></b> 处理 <b><font color="#0000ff">一对一/多对一的关联查询</font></b>。<br><br>在 <association> 元素中通常使用以下属性。<br><ul style="list-style: disc;"><li>property:指定映射到实体类的对象属性。</li><li>column:指定表中对应的字段(即查询返回的列名)。</li><li>javaType:指定映射到实体对象属性的类型。</li><li>select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。</li></ul>
学生类,学生表中有其对应老师的 tid:
StudentMapper 接口中的对应方法:
<span style="orphans: 4; white-space: pre-wrap; word-spacing: 0.05rem; font-family: "Source Sans Pro", "等距更纱黑体 SC", "Helvetica Neue", Arial, sans-serif; font-size: inherit;">多个学生对应一个老师,我们要</span><span style="font-family: "Source Sans Pro", "等距更纱黑体 SC", "Helvetica Neue", Arial, sans-serif; orphans: 4; white-space: pre-wrap; word-spacing: 0.85px;">获取所有学生及对应老师的信息,步骤如下:<br></span>1. 获取所有学生的信息<br>2. 根据获取的学生信息的老师 tid -> 获取该老师的信息<br>3. 这样学生的结果集中应该包含老师,该如何处理呢,数据库中一般使用关联查询:<br> 1. 做一个 <b><font color="#0000ff">结果集映射 resultMap</font></b>:studentAndTeacher<br> 2. studentAndTeacher 结果集的类型为 Student<br> 3. 复杂的属性,单独处理,<b><font color="#0000ff">association 用于对象,collection 用于集合</font></b><br> 4. 学生实体和数据库表的映射关系:学生实体中老师的属性为 teacher(property),对应数据库中为 tid(column)<br> 5. javaType:该关联对象复杂属性在 Student 实体类中的类型<br> 6. select:关联下一个子查询语句<br>
1. 按查询嵌套处理,其实就是分步查询,在每步查询中进行关系映射:<br>
2. 按结果嵌套处理,其实就是单步查询,在最后结果中进行关系映射:
用 getStudents() 输出:
一对多关联查询
在 MyBatis 中,通过 <b><font color="#0000ff"><resultMap></font></b> 元素的子元素 <b><font color="#0000ff"><collection></font></b> 处理一对多的关联查询,<br>collection 可以将关联查询的多条记录映射到一个 list 集合属性中。<br><br>在 <collection> 元素中通常使用以下属性。<ul style="list-style: disc;"><li>property:指定映射到实体类的对象属性。</li><li>column:指定表中对应的字段(即查询返回的列名)。</li><li>javaType:指定映射到实体对象属性的类型。</li><li>select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。</li></ul>
一个老师拥有多个学生,教师类如下:
TeacherMapper 接口中定义的方法如下:
一个教师拥有多个学生,我们要获取指定老师和其所有学生,<b>按结果嵌套 </b>步骤如下:<br>1. 从学生表和老师表中查出学生 id,学生姓名,老师姓名<br>2. 对查询出来的操作做结果集映射<br> 1. 集合使用 collection<br> 2. JavaType 和 ofType 都是用来指定对象类型的<br> 3. JavaType 是用来指定 pojo 中属性的类型<br> 4. ofType 指定的是映射到 list 集合属性中 pojo 的类型<br>
1. 按结果嵌套:
2. 按查询嵌套:
调用上面的方法,输出如下:
0 条评论
下一页