目录
前言
一、Mybatis是什么
二、配置Mybatis环境
三、创建数据库和表
四、添加业务代码
4.1、添加实体类
4.2、添加mapper接口
4.3、添加实现接口方法的xml文件
五、简单的增删改查操作及单元测试
5.1、单元测试
单元测试具体步骤:
单元测试如何才能不污染数据库
5.2、查询操作
不带参数的查询
带参数查询
5.3、 修改操作
接口方法传递对象的操作
5.4、删除操作
5.5、添加操作
添加之后返回受影响行数
添加操作之后返回自增id
5.6、like查询
5.7、#{}和${}的区别
六、使用注解来实现增删改查功能
6.1、@Select注解
6.2、@Insert注解
6.3、@Update注解
6.4、@Delete注解
使用注解的与使用xml方式书写SQL语句的对比
前言
本篇博客主要介绍如何在spring boot项目中配置Mybatis、Mybatis如何连接MySQL数据库、使用Mybatis通过配置文件和注解的实现简单的单表的增删改查操作,还有使用单元测试进行数据库的操作测试。
一、Mybatis是什么
MyBatis 是⼀款优秀的持久层框架,它⽀持⾃定义 SQL、存储过程以及⾼级映射。MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接⼝和 Java POJO(Plain Old Java Objects,普通⽼式 Java 对象)为数据库中的 记录。 简单来说 MyBatis 是更简单完成程序和数据库交互的⼯具,也就是更简单的操作和读取数据库⼯具。
二、配置Mybatis环境
要配置Mybatis环境主要需要两大步骤,首先需要引入Mybaits的框架依赖还有MySQL数据库的驱动依赖,操作如下所示:只需要在创建项目的时候点击添加相关依赖即可
如果在创建时忘记添加可以在创建后在pom.xml中添加。
第二步就是在项目创建好之后在配置文件中设置数据库的连接信息,这一步非常重要,如果没有配置的话,运行项目就会报错。(这里配置以MySQL为例)
配置操作如下:在application.properties中配置
以下内容需要修改的就是url中连接的数据库名称,以及数据库密码,还有xml保存路径信息,其他的一般可以不修改。
# 配置数据库的连接字符串
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8
spring.datasource.username=root
#设置自己数据库密码
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 设置 Mybatis 的 xml 保存路径,以下代表的意思是说明配置文件位于mapper包下以Mapper结尾的xml文件
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 配置打印 MyBatis 执行的 SQL属于debug级别的日志,所以需要设置成debug,项目上线后一般就不要去打印了
logging.level.com.example.blogmybatis=debug
三、创建数据库和表
我们要想操作数据库,那么要操作的数据库是必须有的以及数据库中的表也必须要有。这里我们创建一个userinfo表作为例子演示增删改查操作:代码如下
create table userinfo(
id int primary key auto_increment,
username varchar(100) not null,
password varchar(32) not null,
photo varchar(500) default '',
createtime timestamp default now(),
updatetime timestamp default now(),
`state` int default 1
) default charset 'utf8mb4';
insert into userinfo(username,password) values('zhangsan','123');
四、添加业务代码
4.1、添加实体类
在项目中添加与数据库表相对应的实体类:
创建这个实体类主要是为了可以在项目中使用这个类来接收我们查询返回的信息,只要数据库中的字段名与实体类中属性名一致,框架就会自动的帮我们进行赋值。
package com.example.blogmybatis.model;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class UserInfo {//以下字段名要与数据库中字段名一致
private int id;
private String username;
private String password;
private String photo;
private LocalDateTime createtime;
private LocalDateTime updatetime;
private int state;
}
4.2、添加mapper接口
我们添加mapper接口的目的就是在接口中声明方法,而方法的具体实现是在xml配置文件中的。
代码如下:
package com.example.blogmybatis.model.mapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper//Mapper注解不能省
public interface UserMapper {//在以下类中定义方法
}
4.3、添加实现接口方法的xml文件
这个文件的位置是需要与我们前面的配置文件中设置的路径一致的,需要在mapper目录下,而且以Mapper结尾。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.blogmybatis.mapper.UserMapper">
</mapper>
配置这个需要注意的是,接口的名字和实现接口的xml方法二者之间的名字不一定需要相同,因为二者之间的关联并不是通过这个名字关联的,二者之间是通过namespace属性关联的,所以一旦namespace属性写错了,就会无法正确的实现接口中的方法,执行就会报错。
五、简单的增删改查操作及单元测试
我们这里的增删改查操作都需要现在接口中去声明方法,指定方法返回类型,接着去对应的xml文件中实现接口中声明的方法。
xml中实现方法的具体步骤:
根据要进行的操作,进行选择标签,查询标签就是select,修改标签就是update,删除标签就是delete,增加标签就是insert。接着设置id,id就是接口中的方法名,最后再设置返回类型resultType,这个设置的是返回的基本类型,比如:返回的是List<User>,那么需要设置的就是User类型,而不是List类型。
5.1、单元测试
这里介绍单元测试主要是为了后续可以快捷的测试我们写的代码是否可以正确的操作数据库。
单元测试的概念:
单元测试(unit testing),是指对软件中的最⼩可测试单元进⾏检查和验证的过程就叫单元测试。 单元测试是开发者编写的⼀⼩段代码,⽤于检验被测代码的⼀个很⼩的、很明确的(代码)功能是否正 确。执⾏单元测试就是为了证明某段代码的执⾏结果是否符合我们的预期。如果测试结果符合我们的预 期,称之为测试通过,否则就是测试未通过(或者叫测试失败)。
单元测试的好处:
1、可以⾮常简单、直观、快速的测试某⼀个功能是否正确。
2、使⽤单元测试可以帮我们在打包的时候,发现⼀些问题,因为在打包之前,所以的单元测试必须通过,否则不能打包成功。
3、使⽤单元测试,在测试功能的时候,可以不污染连接的数据库,也就是可以不对数据库进⾏任何改变的情况下,测试功能
Spring Boot中单元测试的使用:
我们要使用单元测试,那首先得有一个单元测试的框架,而我们在创建Spring Boot项目时,Spring已经帮我们内置了一个单元测试的框架了(内置了spring-boot-test),所以这里并不需要我们自己去引入依赖,这个内置的单元测试框架是基于Junit实现的,在pom.xml中就可以看到:如下
单元测试具体步骤:
1.生成单元测试类:
2.编写单元测试代码
单元测试的类是必须加上SpringBootTest注解的,不然是无法正确执行的。
执行之后结果:这个也就是上面查询全部用户信息的结果
当我们在同一个类中再次使用相同的方法生成单元测试时,会出现报Error的情况:直接点击ok即可
单元测试如何才能不污染数据库
我们前面的单元测试,都是直接去操作数据库,修改数据库中的内容,但是我们有时候是并不希望数据库的内容直接被修改的,而只是想要知道执行的结果是否正确。因此Spring Boot中是有提供一个@Transactional注解的,这个注解的作用就是开启一个事务,这个事务在我们测试方法返回前,会执行回滚操作,这个操作就是将我们修改过的数据库内容进行回滚,这样子我们在单元测试时,就不会真的去修改数据库了。
代码演示:(以下为插入数据的操作)
执行结果:从控制台打印的日志信息我们可以直观的看出我们的事务在执行回滚操作了
5.2、查询操作
不带参数的查询
我们在xml文件中写sql语句是不需要带分号的,我们这里的需求是查询数据库中所有用户的信息
以上就是我们一个最简单的查询数据库中所有用户信息的操作。单元测试的结果如下所示:
带参数查询
sql语句中如何接收动态参数:
从上面的sql语句中,我们可以看出,我们可以使用#{}和${}的方式来接收参数的,其中我们只要将参数的名称填入{}中就可以,这里使用#{}和${}之一都可以,至于这两者的区别后面再介绍。
还有带参数查询在接口的方法中我们使用到了@Param注解,这个注解一般都要加上,不加的话有小部分人的程序会报错,这个注解的作用是用来命名的,注解中的名字要求要与我们实现的接口方法中的sql语句中{}中参数名字一致才可以。
执行单元测试的代码及结果:
5.3、 修改操作
现在我们的需求是要将数据库中id为1的用户名改为admin,这时候我们的操作如下:
单元测试的代码及结果:
接口方法传递对象的操作
在上面的update操作中, 我们一共是传递了两个参数,这其实并不是很多,但是,有时候我们是需要传递多个参数进行修改或者查询操作的,但是,这时候我们如果一个参数一个参数的去传,那么我们的形参列表就会变得很长,代码并不美观,可读性可维护性都不强,所以这个时候我们就可以考虑 直接传递一个对象过去,这样子代码就更加的美观了,也更好维护了。
那对象传递过去之后在xml中到底该如何拿到对象中的属性,如何去使用呢?我们直接将上一步的的修改操作的传递参数操作改为传递对象,接下来直接看代码:
单元测试代码及结果: 这里单元测试只需要看返回受影响行数就可以,因为修改成功的话,受影响行数就会是1,修改失败的话受影响行数就会是0
通过代码我们可以得知:传递对象其实和传递参数的区别就在于接口方法中的形参列表的不同,在我们xml中的使用是完全不变的,我们只需要保证xml中#{}中的参数名字与对象中的属性名可以对应上就可以。
5.4、删除操作
删除操作与前面的操作也是类似的,只要使用delete标签就可以了。现在假设我们要把数据库中id为2的用户删了,相应的代码如下:
单元测试代码及结果:
5.5、添加操作
普通的添加操作和之前的操作也是差不多的,普通的添加操作就是在添加之后会返回受影响的行数。但是添加操作中还有一个比较特别的就是,我们有时候需要在添加完之后去返回我们的自增id这个字段,返回自增id这个操作就比较麻烦了,接下去我们直接使用代码来演示这两个操作。
添加之后返回受影响行数
代码如下:
单元测试结果:
添加操作之后返回自增id
代码如下:
单元测试的代码及结果如下:
这里需要注意的就是,我们需要将数据库中的自增主键赋值给某一个属性,所以这里我们一般是使用对象来传参,之后才能将自增主键返回到对象的属性中,不使用对象的话就无法获取这里的自增id了。当然,也可以使用Map来传参,这里就不再演示,因为使用对象传参还是比较主流的写法的。
5.6、like查询
like查询在实际的开发中,还是经常会使用到的,like查询就是给定关键字,然后我们可以去数据库中根据关键字进行查询。假设我们现在要查询名字中含有‘wang’这个关键字的,那么我们的sql就如下所示:
单元测试代码及结果:
关于like查询需要注意的是:我们这里传过来的参数,一般得使用#{}来接收,这里如果使用${}来接收可能就会直接报错,这是因为${}会被认为是常量,而不是变量。换句话说,MyBatis会尝试直接在SQL查询中使用${}
中的值,而不是将其视为一个变量来处理。而且使用${}还有可能会有sql注入的风险,因此like查询建议都使用#{}就不会出现问题。
5.7、#{}和${}的区别
这是一个我们在面试中经常会遇到的一个问题,我们这里先给出二者之间的区别,接着再使用代码来进行解释;
#{}和${}的区别:
1.#{}是安全的,不存在SQL注入的问题,${}是不安全的,存在SQL注入的问题;
2.#{}是预编译处理,而${}是直接替换;
什么是SQL注入:SQL注入的场景有很多,但是简单来说,就是利用SQL语句的漏洞来查询到原本不应该查询到的数据,进而达成某种目的。
SQL注入的代码案例:
从上面的代码我们就可以看出:我们输入的是一个完全错误的密码,但是却可以从数据库中查到正确的数据,所以这就很不安全,可能会被攻击,这就是因为使用${}直接替换的结果。
对于上面的SQL语句的分析:
#{}预编译和${}直接替换的区别:
从图中我们可以看出,使用${}就是直接将参数给替换进去就执行sql,而使用#{}是将sql中的参数先用?这个占位符进行替换,最后再使用set方法来为占位符进行赋值,预编译处理会将参数值作为参数传递给数据库,而不是直接将参数值拼接到SQL语句中,传递给数据库之后数据库就不是使用直接拼接的方式来完成了,数据库是根据参数的值来进行查找的。这样可以防止恶意用户通过参数值注入恶意的SQL代码。
六、使用注解来实现增删改查功能
6.1、@Select注解
代码演示:
单元测试代码及结果:
6.2、@Insert注解
代码演示:
单元测试代码及结果:
6.3、@Update注解
代码演示:
单元测试代码及结果:
6.4、@Delete注解
代码演示:
单元测试及结果:
使用注解的与使用xml方式书写SQL语句的对比
使用注解的优缺点:
优点:
简洁:使用注解可以直接在Java代码中编写SQL语句,不需要额外的XML文件,减少了配置的复杂性。
易于维护:注解方式将SQL语句与Java代码紧密结合,易于理解和维护。所有的SQL语句都在Java代码中,方便查找和修改。
更好的集成性:注解方式适合于简单的SQL语句和快速开发,特别是对于一些简单的CRUD操作,可以减少XML配置的工作量。
缺点:
可读性差:注解方式将SQL语句直接写在Java代码中,可能会导致代码可读性较差,特别是对于复杂的SQL语句。
不利于动态SQL和复杂SQL:注解方式不太适合编写动态SQL,因为注解是静态的,不容易根据条件动态生成SQL语句。
缺乏分离性:注解方式将SQL语句与Java代码紧密结合,缺乏了SQL和Java代码的分离,不利于维护和修改。
使用XML的优缺点:
优点:
可读性好:XML方式将SQL语句和映射配置分离,使得代码更加清晰可读,特别是对于复杂的SQL语句和映射关系。
动态SQL支持:XML方式支持动态SQL,可以根据条件动态生成SQL语句,提供了更大的灵活性。
易于维护:XML方式将SQL语句和映射配置集中在一个地方,便于维护和修改。
缺点:
繁琐:XML方式需要编写额外的XML文件来配置SQL语句和映射关系,相对于注解方式来说,配置的工作量较大。
学习成本高:XML方式需要了解和掌握MyBatis的XML配置规则,对于新手来说,学习成本可能较高。
不够直观:相对于注解方式,XML方式的配置不够直观,需要在XML文件中编写SQL语句和映射关系。
总的来说,一般是会使用xml的方式,因为xml的方式能够写动态SQL和复杂的SQL,但是如果项目比较简单也可以使用注解的方式。