【Mybatis】关于Mybatis手写xml文件的常见问题

明天就是端午节啦

博主今天先提前祝大家端午节快乐呀!!

文章目录


前言

开发日常中我们常常用到SSM,SSH等框架,==这篇主要就是总结一些在使用Mybatis的时候,如果我们手写XML的SQL语句的话,需要注意的一些问题和概念;==能帮助我们更好的进行开发和及时发现bug;

提示:这里罗列的主要是我以前手写xml中sql语句语法中,一些容易出错的,和一些模糊的概念点做了梳理;学习中有同样困扰的小伙伴可以看看


一、尽量做到参数化查询

什么是参数化查询,就是在写查询语句的时候,使用 #{} 语法来引用参数,而不要用 ;这里 {};这里 ;这里{}作用我们知道是用来替换sql字符串的值的,这个通常会带来sql注入攻击的问题;这是一个代码编写的习惯问题,我们需要尽量避免;

(注:SQL注入简单的理解来说,就是通过插入恶意的SQL代码,来执行一些我们不需要的数据库操作;)

二、关于@param注解

该注解主要我们使用在Mapper定义接口方法中,他往往与我们在Mapper XML中的参数所对应;

举个🌰:

XML文件中我们写了一个查询,id作为参数:

<select id="selectUserById" resultType="User">  
    SELECT * FROM users WHERE id = #{id}  
</select>

// Mapper 接口
public interface UserMapper {  
    User selectUser(@Param("id") int id);  
}

刚接触mybatis的小伙伴多少会不理解为啥有时候需要写这个注解,有时候又没有写;

这是因为,@param 对于多参数情况下我们才会去使用,因为mybatis无法确定哪个参数对应哪个,而单参数下,mybatis能根据我们参数的类型自动处理,无需显式使用,还有就是遇到map类型作为单参数时,我们也会发现常见的做法是不写@param注解的,查询语句中也是直接通过键值获取的;

例如:

// XML 
<select id="selectUser" resultType="User">  
    SELECT * FROM users WHERE id = #{id} AND name = #{name}  
</select>

// Mapper 接口 
public interface UserMapper {  
    User selectUser(@Param("id") int id, @Param("name") String name);  
}

另外:@param注解同时还能对应复杂的参数,如我们自定义的一些实体对象(JavaBean等);

例如:下面就是以User bean为参数传递,查询sql中直接使用bean的属性作为参数进行查询

// Mapper 接口 
public interface UserMapper {  
    List<User> selectByUser(@Param("user") User user);  
}

// XML 
<select id="selectByUser" resultType="User">  
    SELECT * FROM users WHERE name = #{user.name} AND age = #{user.age}  
</select>

因此,有时候为了代码更好的可读性,其实一个参数时我们也能把@param注解加上,这并没有什么问题;当遇到多个参数中既包含基本类型参数,又包含复杂类型参数的,我们更多的考虑将他们封装为一个查询DTO去处理会更好

三、mybatis处理特殊字符

在mybatis中处理特殊字符,如 <、>、& 等时,转义字符<![CDATA[ ]]>(CDATA 标记)是两种常用的方法,但是他们分别也有不同使用场景;

1.转义字符

转义字符是将特殊字符替换为特定的转义序列,我们常见的有这些:

下面展示一些 常见的转义符

< 替换为 &lt;
> 替换为 &gt;
& 替换为 &amp;
" 替换为 &quot;
' 替换为 '

🌰:例如这里就是对于>的转义

但是其实大家在实际编码会发现,对于这个符号,似乎不转义,mybatis也不会解析错误,这是为什么?

因为这个符号比较特殊一些,>符号在mybatis的解析中是一个结束标签标识,通常不会被解析器认为是标签的一部分,相对的<就会被认为是一个标签的开始而不是一个文本来解读,在解析的时候就会出错;

适用场景与特点

1、转义前后的字符都会被 XML 解析器解析,所以大量转义字符存在时,相对比较损耗性能
2、转义字符适用于所有情况,因为任何特殊字符都可以被转义,因此更通用
3、短字符串时的转义中常用的选择,可读性高

2.<![CDATA[]]>(CDATA 标记)

CDATA 标记他的作用简单的来说,就是告诉我们的mybatis解析器,忽略我[]中的字符,直接将其视为纯文本来对待;

🌰:例如,下面的例子中是<即对该符号的转义。<![CDATA[要转义的内容]]>

适用场景与特点

对于长字符串来说,使用 CDATA 标记会相对更简洁,因为它避免了大量的转义字符的操作,并且解读起来也相对容易;

1、CDATA 标记不能包含 ]]> 字符串,会与自身的结束符号冲突
2、不能嵌套使用
3、书写的时候也要注意]]> 结尾部分不能包含空格或换行
4、转义后的字符不会被 XML 解析器解析,而直接认定为文本处理,所以性能上更好

四、结果映射

在MyBatis中,结果映射是一个非常重要的部分,它负责将数据库查询的结果集映射到Java对象的属性上;通常在这块有几个地方需要去了解;

1、映射好文件与接口 namespace

即映射文件的名称空间(namespace)必须与Mapper接口的全路径名保持一致

2、statementId的映射关系

映射文件中<select>的statementId(即SQL语句的ID)必须与Mapper接口中的方法名一致

3、parameterType属性

这个属性在一般情况下不是必须的,因为mybatis都能自动识别参数类型,但是如果无法推断类型,即参数可能比较复杂的,就需要我们进行指定;例如一些我们自定义的一些实体对象就可以去指定,但是如果你前面已经使用了@param注解参数了,就不需要指定parameterType了;因为mybatis会根据注解去处理

4、resultType

resultType属性用于指定查询返回结果集中数据的类型。它可以是Java的基本类型、包装类型、字符串、集合类型或自定义的Java对象。我们更常见的还是映射到我们JavaBean对象中

如果数据库中查询结果能和bean对象完全对应,则选择resultType;

// 自定义的对象
public class User {  
    private Integer id;  
    private String name;  
    // getters and setters  
}

// xml文件中直接映射到对象上
<select id="selectUsers" resultType="com.example.User">  
    SELECT id, name FROM users  
</select>

5、resultMap

resultMap可以理解为是resultType的升级版本,他能更好的提供复杂的关系映射;
通常如果数据库中查询结果不能和beand对象完全对应,并且会用到一些关联映射关系,则此时选择的就是resultMap替代resultType;

通常的用法:

<!-- 在 MyBatis 的 mapper XML 文件中 -->  
<resultMap id="userResultMap" type="User">  
    <id property="id" column="user_id" />  
    <result property="username" column="username" />  
    <association property="profile" javaType="Profile" column="user_id" resultMap="profileResultMap" />  
</resultMap>  

5.1 resultMap属性

<resultMap>中id = "userResultMap"是resultMap的标识,用于后续查询的结果集引用;例如下面的查询语句,就需要保持resultMap的值与上面定义的id一致;

<select id="selectUserWithProfile" resultMap="userResultMap">  
    SELECT u.*, p.*  
    FROM user u  
    LEFT JOIN profile p ON u.user_id = p.user_id  
    WHERE u.user_id = #{userId}  
</select>

type属性是指定要映射到的Java类型,即我们定义的对象;

5.2 resultMap子标签

<resultMap>标签里的<id>标签用于设定我们映射的java对象主键与数据库的主键对应关系,<result>就是其他的属性映射关系定义,property就是Java对象的属性字段,colunm就是数据库字段,一一对应上即可;

<association>是一个从 User 到 Profile 的关联;属性javaType代表关联的Java对象,属性column就是关联的键值字段;

但是通常它只用于一对一的关联关系,如果这里关系是一对多的情况,我们就会用到另一个元素<collection>==;

<collection>属性基本和<association>中一致;但是会多一个ofType属性来指定集合中元素的Java类型

总的来说:
1、数据库字段和Java对象属性不一致:当数据库字段名与Java对象的属性名不同时,可以使用resultMap来指定映射规则。

2、复杂的Java对象:当Java对象包含其他Java对象或集合时,可以使用<association>和<collection>元素来处理关联关系。

五、最后的最后

喜欢博主内容的伙伴们可以三连支持一下,我们一起进步~

相关推荐
V+zmm101345 分钟前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
Oneforlove_twoforjob30 分钟前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存
xmh-sxh-131432 分钟前
常用的缓存技术都有哪些
java
AiFlutter1 小时前
Flutter-底部分享弹窗(showModalBottomSheet)
java·前端·flutter
J不A秃V头A2 小时前
IntelliJ IDEA中设置激活的profile
java·intellij-idea
DARLING Zero two♡2 小时前
【优选算法】Pointer-Slice:双指针的算法切片(下)
java·数据结构·c++·算法·leetcode
小池先生2 小时前
springboot启动不了 因一个spring-boot-starter-web底下的tomcat-embed-core依赖丢失
java·spring boot·后端
CodeClimb2 小时前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
程序员厉飞雨2 小时前
Android R8 耗时优化
android·java·前端
odng2 小时前
IDEA自己常用的几个快捷方式(自己的习惯)
java·ide·intellij-idea