栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis系列全解(五):全网最全!详解Mybatis的Mapper映射文件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis系列全解(五):全网最全!详解Mybatis的Mapper映射文件

封面:洛小汐
作者:潘潘

若不是生活所迫,谁愿意背负一身才华。

前言

上节我们介绍了 《 Mybatis系列全解(四):全网最全!Mybatis配置文件 XML 全貌详解 》,内容很详细( 也很枯燥),由于篇幅实在过于冗长,我预计大家想看完得花上两段上班地铁公交车的时间 。。。

不过应该有让大家了解到 Mybatis 的核心配置文件 config.xml 全貌,其中的 元素即是我们本节准备登场介绍的 SQL 映射器,上节有介绍了三种引入 SQL 映射器的方式,本节我们就主要聊聊它的几个顶级元素用法。

Mybatis 真正强大就在于它的语句映射,这是它的魔力所在,也是基石。由于它异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码( 95% 是Mybatis 官网的说法 ,我也就引入一下 ),MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。

Mybatis系列全解脑图分享,持续更新中


Mybaits系列全解 (持续更新)
  • Mybatis系列全解(一):手写一套持久层框架
  • Mybatis系列全解(二):Mybatis简介与环境搭建
  • Mybatis系列全解(三):Mybatis简单CRUD使用介绍
  • Mybatis系列全解(四):全网最全!Mybatis配置文件XML全貌详解
  • Mybatis系列全解(五):全网最全!详解Mybatis的Mapper映射文件
  • Mybatis系列全解(六):Mybatis最硬核的API你知道几个?
  • Mybatis系列全解(七):全息视角看Dao层两种实现方式之传统方式与代理方式
  • Mybatis系列全解(八):Mybatis的动态SQL
  • Mybatis系列全解(九):Mybatis的复杂映射
  • Mybatis系列全解(十):Mybatis注解开发
  • Mybatis系列全解(十一):Mybatis缓存全解
  • Mybatis系列全解(十二):Mybatis插件开发
  • Mybatis系列全解(十三):Mybatis代码生成器
  • Mybatis系列全解(十四):Spring集成Mybatis
  • Mybatis系列全解(十五):SpringBoot集成Mybatis
  • Mybatis系列全解(十六):Mybatis源码剖析

目录

1、mapper 映射器顶级元素全貌

2、namespace 命名空间

3、select 查询

4、insert / update / delete 增删改

5、cache 缓存

6、cache-ref 缓存引用

7、sql 语句块

8、parameterMap 参数映射

9、总结

mapper 映射器顶级元素全貌

与其它 ORM 框架如 Hibernate 不同,Mybatis 的框架思想希望开发者能够直接操作数据库编写 SQL,而不是隐藏起来,让开发者独自面对 Java 对象,为此 Mybatis 设计了 SQL 映射器,任你五招十二式。

映射器有九大顶级元素 ,基本技能介绍

  • select : 用于查询,支持传参,返回指定结果集;
  • insert : 用于新增,支持传参,返回指定结果集;
  • update : 用于更新,支持传参,返回指定结果集;
  • delete : 用于删除,支持传参,返回指定结果集;
  • sql : 被其它语句引用的 可复用 语句块;
  • cache : 当前命名空间缓存配置;
  • cache-ref : 引用其它命名空间的缓存配置;
  • parameterMap : 参数映射,已弃用,是它不够好;
  • resultMap : 结果集映射,它就很好;

其中,增删改查操作拼接 SQL 时使用到的 动态SQL( if、where、foreach啥的),以及封装结果集时使用到的 复杂映射 (1对1 ,1对多,多对多啥的),这两部分我们后面单立文章再详细介绍,本文中我们简单点过。

九大顶级元素 ,功能归类:

其中顶一元素 parameterMap 已建议弃用了 。

无论你有多么复杂的 SQL 操作,最根本的思路都逃不出以上 4 部分。

namespace 命名空间

一个完整的 Mapper 映射文件,需要有约束头 xml 与 !DOCTYPE ,其次才是 mapper 根元素,最后再是顶级元素,而其中,namespace 属性作为 mapper 的唯一标识,试回忆:

  • 上学时,6年级一班23号,能代表唯一的你。
  • 编写 Java 类时,包名 + 类名,能代表唯一的类。
  • 而如今,我们在 Mybatis 中写的每一段 SQL 语句,同样有唯一的代表方式,那就是「 命名空间标识 + 语句id 」,无论是为了区分业务也好,还是为了拆分服务也好,反正 Mybatis 让每一个 mapper.xml 配备一个唯一命名空间标识。

每一段 SQL 语句都是唯一定义的,我们在 Mybatis 中用「 命名空间标识 + 语句块 ID 」作为唯一的标识,组合之后在 Mybatis 二级缓存中可以作为本地 map 集合 缓存 的唯一Key ,也可以用于 Dao 接口的 映射 绑定,还能作为唯一 代理 标识。总之,我们希望避免命名冲突和重复定义,所以,拥有这么一个唯一标识 ,它就至少有一亿个利好。

select 查询

select 查询语句,几乎是我们最高频的使用元素,所以 Mybatis 在这块没少下功夫,目的就是通过提供尽可能多的便利,让我们的查询操作变得简单。 一个查询用户 User 的查询语句可以这么编写:


  select * from t_user where id = #{id}

注意参数符号:

#{id}

#{} 告诉 MyBatis 创建一个预编译语句(PreparedStatement)参数,在 JDBC 中,这样的一个参数在 SQL 中会由一个 “ ? ” 来标识,并被传递到一个新的预编译语句中,就像这样:

// 近似的 JDBC 代码,非 MyBatis 代码...
String selectUser = " select * from t_user where id = ? ";
PreparedStatement ps = conn.prepareStatement(selectUser);
ps.setInt(1,id);

#{} 作为占位符,${} 作为替换符,两者没有孰轻孰重,只不过应用场景不同,适当取舍即可。

我们希望完成类似 JDBC 中的 PrepareStatement 预编译处理 ,可以使用 #{} ,它会在替换占位符时首尾添加上单引号 ‘’ ,能有效防止 SQL 注入 风险。

例如使用 ${} 操作删除 ( 就很有问题!)

// 1、使用 ${} 有注入风险
delete from t_user where id = ${id}

// 2、正常传值,id 传入 1  
delete from t_user where id = 1
// 结果删除了id=1 的记录
    
// 3、注入风险,id 传入 1 or 1=1 
delete from t_user where id = 1 or 1=1
// 全表删除了

再看看 #{} 是如何规避 SQL 注入 的:

// 1、使用 #{} 有效防止注入风险
delete from t_user where id = #{id}

// 2、正常传值,id 传入 1   
delete from t_user where id = '1'
// 结果删除了id=1 的记录
    
// 3、注入风险,id 传入 1 or 1=1 
delete from t_user where id = '1 or 1=1'
// SQL 语句报错,表数据安全

虽然在防止 SQL 注入方面,${} 确实无能为力,不过我们 ${} 在其它方面可不容小觑,例如它允许你灵活地进行 动态表和动态列名的替换 操作,例如:

// 1、灵活查询指定表数据
select * from ${tableName} 

// 传入 tableName参数 = t_user , 结果
select * from t_user  

// 2、灵活查询不同列条件数据
select * from t_user where ${colunmName} = ${value}

// 传入 colunmName参数 = name , value参数 = '潘潘', 结果
select * from t_user where name = '潘潘'

// 传入 colunmName参数 = id , value参数 = 1, 结果
select * from t_user where id = 1

以上的 ${} 替换列名与表名的方式非常灵活,不过确实存在 SQL 注入风险,所以在考虑使用 #{} 或 ${} 前,需要评估风险,避免风险,允许的情况下,我建议使用 #{} 。

当然,select 元素允许你配置很多属性来配置每条语句的行为细节。


  select
    
 
    ,
    
 
    
  from t_user t1 cross join t_user t2

也可以在 include 元素的 refid 属性或多层内部语句中使用属性值,例如:


  ${prefix}_user



  from
    



parameterMap 参数映射

parameterMap 元素官方已经不建议使用,并且再后续版本会退出舞台。首先对于我们 Java 来说,特别不希望在代码中通过传递 map 来传参,这样对于后续维护或者参数查找都是极不负责任的,我们推荐使用 JavaBean 来传值参数,这是 parameterMap 被抛弃的其中一个原因;另外也由于 parameterType 属性的诞生就能很好的代替 parameterMap ,并且还能自定义 JavaBean 类型的传参,所以 parameterMap 退出舞台,实属正常。

总结

我一直来都希望自己只输出观点,而不是输出字典,但其中有些知识点又是极其冗杂,知识输出真是个难搞的差事,如何既能把知识脉络梳理的完整,又能讲得浅显易懂,言简意赅,确实是后续文章分解输出的研究方向。

本篇完,本系列下一篇我们讲《 Mybatis系列全解(六):Mybatis最硬核的API你知道几个? 》。

BIU ~ 文章持续更新,本文会在 GitHub github.com/JavaWorld 收录,热腾腾的技术、框架、面经、解决方案,我们都会以最美的姿势第一时间送达,欢迎 Star。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号