MyBatis扩展

目录

单元测试

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项目创建的时候会默认帮我们添加单元测试的框架.MyBatis扩展_第1张图片

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

MyBatis扩展_第2张图片


 spring boot的单元测试的使用

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

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

MyBatis扩展_第3张图片


 2.点击test

MyBatis扩展_第4张图片


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

MyBatis扩展_第5张图片


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

MyBatis扩展_第6张图片

MyBatis扩展_第7张图片

MyBatis扩展_第8张图片


5.运行单元测试

MyBatis扩展_第9张图片


6.查看测试结果

MyBatis扩展_第10张图片

MyBatis扩展_第11张图片


追加测试方法

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

MyBatis扩展_第12张图片

MyBatis扩展_第13张图片

MyBatis扩展_第14张图片


 断言

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


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

MyBatis

单表传参查询

MyBatis扩展_第15张图片

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


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

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

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

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

MyBatis扩展_第16张图片

直接替换:

MyBatis扩展_第17张图片

占位符:

MyBatis扩展_第18张图片


两者的区别:

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

根据名称来查询用户:

先使用占位符的方式:

 MyBatis扩展_第19张图片 一切正常.

使用直接替换的方式:

MyBatis扩展_第20张图片

MyBatis扩展_第21张图片

报错了,因为是直接替换

MyBatis扩展_第22张图片

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

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

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


 安全问题sql注入

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

 MyBatis扩展_第23张图片

MyBatis扩展_第24张图片 当我们使用#{}时,是安全的,不会发生sql注入.我们改成${},看sql注入是如何发生的.

MyBatis扩展_第25张图片

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

MyBatis扩展_第26张图片

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

MyBatis扩展_第27张图片

MyBatis扩展_第28张图片

MyBatis扩展_第29张图片

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

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

MyBatis扩展_第30张图片

这就发生了sql注入.

MyBatis扩展_第31张图片

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

MyBatis扩展_第32张图片

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

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

MyBatis扩展_第33张图片

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

MyBatis扩展_第34张图片

MyBatis扩展_第35张图片

使用#{}就会报错. 


单表修改操作

userMapper:

MyBatis扩展_第36张图片

 xml:MyBatis扩展_第37张图片

单元测试:

MyBatis扩展_第38张图片

MyBatis扩展_第39张图片

MyBatis扩展_第40张图片

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

MyBatis扩展_第41张图片

MyBatis扩展_第42张图片

MyBatis扩展_第43张图片

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


单表删除操作

MyBatis扩展_第44张图片

MyBatis扩展_第45张图片

MyBatis扩展_第46张图片

 MyBatis扩展_第47张图片


单表添加操作

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

呢?

MyBatis扩展_第48张图片

MyBatis扩展_第49张图片

单元测试的结果:

MyBatis扩展_第50张图片

MyBatis扩展_第51张图片

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

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

like模糊匹配查询

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

在UserMapper里实现方法声明:

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

生成单元测试代码并启动: MyBatis扩展_第52张图片

启动之后发现报错了.

MyBatis扩展_第53张图片

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

MyBatis扩展_第54张图片

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

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

MyBatis扩展_第55张图片

MyBatis扩展_第56张图片


返回字典映射resultMap

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

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

resultMap定义是在xml中的.

MyBatis扩展_第57张图片

MyBatis扩展_第58张图片

启动单元测试:

MyBatis扩展_第59张图片

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

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

MyBatis扩展_第60张图片


多表查询

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

MyBatis扩展_第61张图片

创建一个ArticleInfo实体类

MyBatis扩展_第62张图片

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

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

MyBatis扩展_第63张图片

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

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

MyBatis扩展_第64张图片

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

MyBatis扩展_第65张图片

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

MyBatis扩展_第66张图片

启动单元测试

MyBatis扩展_第67张图片

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

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

MyBatis扩展_第68张图片解决这个问题.只需要重写toString方法即可.当我们重写toString之后,lombok的toString就会不起作用.

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

MyBatis扩展_第69张图片

MyBatis扩展_第70张图片

再次启动单元测试:

MyBatis扩展_第71张图片


动态SQL的使用

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

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

为什么要使用动态sql

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

MyBatis扩展_第72张图片

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

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

MyBatis扩展_第73张图片

默认值是1.

MyBatis扩展_第74张图片


if标签

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

MyBatis扩展_第75张图片

方法实现:

MyBatis扩展_第76张图片 生成单元测试:

不传photo

MyBatis扩展_第77张图片

传photo:

MyBatis扩展_第78张图片

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


trim标签

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

MyBatis扩展_第80张图片


where标签

MyBatis扩展_第81张图片


set标签

MyBatis扩展_第82张图片

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


foreach标签

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

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

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

MyBatis扩展_第83张图片

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

你可能感兴趣的:(mybatis,java,单元测试)