MyBatis扩展

文章详细介绍了如何在SpringBoot中进行单元测试,包括测试步骤、断言的使用,并探讨了MyBatis的动态SQL功能,如if、trim、where、set和foreach标签,以及它们在单表操作和多表查询中的应用,强调了动态SQL在处理非必填字段和安全问题(SQL注入)上的重要性。
摘要由CSDN通过智能技术生成

目录

单元测试

spring boot的单元测试

 spring boot的单元测试的使用

1.在要测试的类里,右键点击生成

 2.点击test

3.配置测试的信息,点击ok

4.在生成的测试类里,加注解,写测试代码

5.运行单元测试

6.查看测试结果

追加测试方法

 断言

MyBatis

单表传参查询

 MyBatis获取动态参数有两种实现

 安全问题sql注入

单表修改操作

单表删除操作

单表添加操作

like模糊匹配查询

返回字典映射resultMap

多表查询

动态SQL的使用

为什么要使用动态sql

if标签

trim标签

where标签

set标签

foreach标签


单元测试

单元测试(unit testing)是指对软件中的最小可测试单元进行检查和验证的过程就叫做单元测试.

单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的,很明确的代码功能是否正确.执行单元测试就是为了证明某段代码的执行结果是否符合我们的预期.如果测试结果符合我们的预期,称之为测试通过,否则就是测试未通过.

单元测试的好处

  1. 可以简单直观快速的测试某一个功能是否正确.
  2. 使用单元测试可以帮我们在打包的时候,发现一些问题,因为在打包之前,所有的单元测试必须通过,否则不能打包成功.
  3. 使用单元测试,在测试功能的时候,可以不污染数据库中的数据,也就是说可以不对数据库进行任何改变的情况下来测试功能.
  4. 可以跳过系统限制(比如登录校验),直接测试代码功能.

spring boot的单元测试

Spring Boot项目创建的时候会默认帮我们添加单元测试的框架.

 这个单元测试的框架主要是依靠另一个著名的测试框架JUnit实现的.


 spring boot的单元测试的使用

我们要测试UserMapper中的getUserById这个方法.

1.在要测试的类里,右键点击生成


 2.点击test


3.配置测试的信息,点击ok


4.在生成的测试类里,加注解,写测试代码


5.运行单元测试


6.查看测试结果


追加测试方法

如果要在生成userMapper中的getall方法,还是按照上述的方式,只不过在生成测试类的时候,会报一个error,点击ok即可.


 断言

单元测试也可以搭配断言来使用.


 在掌握了单元测试之后,我们就可以在写MyBatis的时候,边写边测试.

MyBatis

单表传参查询

@Param就是给传递的参数起名字,当里面写成uid的时候,xml里也要用${uid}来接收.


 MyBatis获取动态参数有两种实现

1.${paramName} ,这种方式是直接替换.

2.#{paramName},这种方式是采用占位符的模式.

验证上述两种模式,我们可以在配置文件里进行配置,来打印MyBatis执行的sql

直接替换:

占位符:


两者的区别:

在使用上,传递一个int的类型的数据,看不出两者的区别,我们来传递一个varchar类型的数据.

根据名称来查询用户:

先使用占位符的方式:

  一切正常.

使用直接替换的方式:

报错了,因为是直接替换

生成的sql里张三没有加上单引号,所以报错了.

因为是直接替换,在查询varchar类型的数据的时候,由于没有单引号,所以会报错.

解决这个问题,我们可以手动加上单引号,这样可以不报错,但是直接替换不能保证我们的安全问题.


 安全问题sql注入

sql注入时常发生在登录中,用了一个不正确的用户密码,但是依然查询到了数据,所以我们模拟一个登录环境:

 

 当我们使用#{}时,是安全的,不会发生sql注入.我们改成${},看sql注入是如何发生的.

为了方便演示,我们数据库中的用户表中的内容只有一条数据.

生成测试代码,看其能否正确查询到用户信息:

正确的用户名密码可以查询到,错误的用户密码查询不到.

接下来,把密码设置成比较奇怪的一段字符:

这就发生了sql注入.

但是我们将${}改为#{}就没有这个问题:

这就说明${}存在安全性问题,#{}没有安全问题.

#{}采用的是预执行,而${}采用的是及时执行.#{}没有sql注入的问题,但是它是识别不了sql关键字的,当我们有些场景需要传递sql关键字的时候,使用#{}就不行了.

 降序升序传递的就是sql的关键字..

使用#{}就会报错. 


单表修改操作

userMapper:

 xml:

单元测试:

如果想让测试的数据不污染数据库,在单元测试方法上面加一个注解即可.

数据库的数据没有改变. 执行完之后进行一个回滚操作.


单表删除操作

 


单表添加操作

我们在添加用户的时候,除了返回受影响的行数之外,还希望得到添加的用户的id,这个应该怎么实现

呢?

单元测试的结果:

 useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据

库内部⽣成的主键,默认是false.
keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值insert 语句的 selectKey ⼦元素设置它的值.默认值:未设置(unset)。如果⽣成列 不⽌⼀个,可以⽤逗号分隔多个属性名称。

like模糊匹配查询

我们实现根据用户名来模糊查询.

在UserMapper里实现方法声明:

在UserMapper.xml里实现方法的具体实现:

生成单元测试代码并启动: 

启动之后发现报错了.

报错的原因就是:我们使用#{}是占位符的方式

 所以,它会根据我们传递的参数类型来判断是否加单引号,由于我们传递的是String类型,所以最终生成的sql:

解决这个问题,我们可以使用mysql的内置函数concat,它的作用就是实现字符串的拼接.


返回字典映射resultMap

当实体类中的属性名称(pwd)和数据库中表的字段名称(password)不一致时,Mybatis就无法实现属性和字段的映射了.

在此种场景下,我们可以使用resultMap字典映射.此外resultMap也可以应用在一对一和一对多的关系查询中.

resultMap定义是在xml中的.

启动单元测试:

虽然名称不一致,但是由于我们设定了字典映射,所以返回的password依然能够映射到pwd上.

面对属性字段名称不一致的情况,我们还可以使用mysql的重命名,对查询的结果集的字段进行重命名.


多表查询

实现通过文章的id来查询文章表的详情页查询,除了要查询文章表的字段之外,还要知道文章的作者是谁.

创建一个ArticleInfo实体类

创建一个 ArticleInfoVO类,因为我们要查询的内容不只是文章表的,所以要使用到vo(value object).

vo中文翻译为'值对象',是一种特殊的Java Bean,与Entity相比,vo的作用更多是用于传递一些特定的数据,而不是表现整个业务实体数据.其属性通常是只读的.vo的属性通常是多个表或者其他来源手机并组装成的,用于集合多表数据.

我们只需要让其继承自ArticleInfo,在加一个username 属性即可,不必在把ArticleInfo的属性在写一遍.

创建ArticleMapper,加@Mapper注解,声明方法

创建 ArticleMapper.xml,进行方法的具体实现

生成单元测试,加@SpringBootTest注解,引入ArticleMapper

启动单元测试

发现只打印了子类的属性,没有打印父类的属性.

出现这个问题的原因就是,我们使用了lombok的@Data注解,生成的子类的toString方法默认是不打印父类属性的.这一点我们可以查看生成的target来验证.

解决这个问题.只需要重写toString方法即可.当我们重写toString之后,lombok的toString就会不起作用.

右键生成,点击toString(),选择本类+父类的模板.点击ok.

再次启动单元测试:


动态SQL的使用

动态 sql 是Mybatis的强⼤特性之⼀,能够完成不同条件下不同的 sql 拼接 .

就是允许在xml里面写逻辑判断.不同的执行生成的sql可能不同.

为什么要使用动态sql

在添加用户的时候会有这么一个场景:

必填字段和非必填字段.对于非必填字段,用户填入了,就在数据库正常插入即可.如果用户没有填,那么传过来就是null,如果不使用动态sql,在数据库中就插入了null值,但是我们期望的是用户不填我们就使用该字段的默认值,而不是null值.

我们就拿用户表中的state字段举例:

默认值是1.


if标签

模拟添加用户的时候photo是非必传的 .

方法实现:

 生成单元测试:

不传photo

传photo:

两次生成的sql是不同的,这就是动态sql.


trim标签

<trim>标签结合<if>标签,对多个字段都采取动态⽣成的⽅式。
<trim>标签中有如下属性:
prefix:表示整个语句块,以prefix的值作为前缀
suffix:表示整个语句块,以suffix的值作为后缀
prefixOverrides:表示整个语句块要去除掉的前缀
suffixOverrides:表示整个语句块要去除掉的后缀
在三个都是非必填的时候,仅仅使用if标签无法解决问题,原因就是对于sql中的逗号无法处理.


where标签


set标签

set标签用来修改操作的时候,它会帮我们自动生成set(set标签内容不为空的时候),也会帮我们自动去除逗号后缀.


foreach标签

对集合进⾏遍历时可以使⽤该标签。<foreach>标签有如下属性:

collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象

item:遍历时的每⼀个对象
open:语句块开头的字符串
close:语句块结束的字符串
separator:每次遍历之间间隔的字符串
<foreach>标签应用的场景就是在进行批量删除的时候.
像根据id删除文章的时候:

collection就是方法中的集合参数名称.
item就是遍历的每一个对象,名称是我们自己起的,用于在下面#{}拿到对象.
open前缀close后缀
separator间隔符.
生成的sql语句:
delete from article where id in (1,2,3);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值