MyBatis-Plus (baomidou.com)
一 MyBatis-Plus简介
- 增强工具。只做增强不做改。
- 可以直接在mybatis的基础上整合mybatis-plus。此时并不会影响mybatis的功能,即mybatis原来的功能都在,该怎么用还怎么用。锦上添花的是还能使用mybatis-plus提供的:通用的mapper、通用的service、在不编写任何sql语句的基础上快速完成单表的CRUD、批量操作、逻辑删除、分页、优秀插件的使用、多数据源的配置等待功能。
- 框架结构
- 右半部分:mybatis-plus的组成部分,共同支持mybatis-plus的功能实现
- mybatis-plus-boot-starter:mybatis-plus本身的启动器
- annotation:注解部分
- extension:扩展部分
- core:核心部分
- generator:代码生成部分
- 左半部分:展示了mybatis-plus该如何来实现功能
- 第一步:Scan Entity:扫描实体类
- 在开发过程中,为什么不需要手写sql语句(mybatis需要)呢?因为mybaits-plus中sql语句都是动态生成的,所以第一步要扫描要操作的实体类(当前操作的表由实体类决定)。
- 第二步:Reflection extraction:反射抽取
- 经过实体类的扫描以后,通过反射抽取实体类中的属性。
- 第三步:Analysis Table Name Column
- 抽取出实体类中的属性以后,分析实体类和表之间的关系、分析实体类属性与表字段之间的关系。
- 第四步:SQL: Insert Update Delete Select:当前调用的CRUD方法
- 分析完成以后,根据当前我们调用的CRUD方法,生成相对应的sql语句。
- 调用的CRUD方法?因为mybatis-plus提供了通用的mapper、通用的service。
- 分析完成以后,根据当前我们调用的CRUD方法,生成相对应的sql语句。
- 第五步:Injection Mybatis Container:sql语句注入到mybatis容器中,从而实现最终的功能。
- 第一步:Scan Entity:扫描实体类
- 右半部分:mybatis-plus的组成部分,共同支持mybatis-plus的功能实现
二 基本功能
1 通用mapper
- 概述
- 通用mapper中包含的CRUD方法,它们的返回值都是int类型的,指向的是受影响的行数。
- List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
- 单独使用mybatis的工程:mybatis中我们的查询方法可以返回实体类对象,也可以查询并返回一个List集合,也可以查询并返回一个map集合。
- 使用mybatis-plus的工程:同理。也可以。
- 入门案例
- 第一步:mysql
- 第1步:创建数据库入表
- id,主键,bigint(20)。因为在通过mybatis-plus进行数据插入的时候,它默认用雪花算法来生成id,这样一来id的长度会比较长,所以这里使用的是bigint而非int。
- 第1步:创建数据库入表
- 第二步:idea
- 第1步:创建spring boot工程
- 第2步:pom.xml
- 第a步:lombok依赖。
- 第3步:idea插件安装
- 第a步:idea安装lombok插件。
- 第4步:application.yml
- 第a步:数据源类型:type: com.zaxxer.hikari.HikariDataSource(此类型:springboot中默认使用的数据源类型)
- 第b步:jdbc:mysql://localhost:3306/mysql?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
- characterEncoding:连接数据库、操作数据库时使用的编码格式。
- serverTimezone=GMT%2B8:中国时区的配置(mysql8独有配置)
- useSSL=false:mysql5和mysql8都要使用此参数
- 第5步:编码
- 第a步:实体类User.java:因为数据库中的表要和实体类做映射关系;
- private Long id:因为数据库表中id使用的是bigint类型,按照数据类型的范围来说,实体类这里最好使用Long类型进行映射(接收)。
- @Data :这是lombok注解。虽然在当前实体类中看不到构造器(有参、无参)、get/set方法,但是经过maven 》complie把当前的工程编译以后,在target 》classes 》User.class会看到构造器、get/set方法、equal方法、tostring方法
- maven打包错误: Failed to execute goal org.apache.maven.pluginsmaven-resources-plugin3.2.0resources
- pom.xml中springboot版本:<version>2.6.3</version>
- pom.xml中jdk版本:<java.version>8</java.version>
- 第b步:添加mapper接口:UserMapper.java,并使用mybatis-plus提供的通用mapper
- 单独使用mybatis的工程:mapper接口中的方法和sql语句都是需要我们手动去写的。
- 使用mybatis-plus的工程:使用mybatis-plus提供的通用mapper、通用service功能,快速实现单表的CRUD。
- public interface UserMapper extends BaseMapper<User>:BaseMapper中包含了很多很多mybatis-plus提供方法
- CRUD方法
- 第c步:启动类
- 单独使用mybatis的工程:设置mapper接口所在的包、映射文件所在的包。
- 使用mybatis-plus的工程:同样需要。
-
//用于扫描mapper接口所在的包 //或者所用于扫描指定包下的mapper接口 @MapperScan("com.atguigu.mapper")
- 第d步:测试类
- 单独使用mybatis的工程:首先,需要在UserMapper中创建接口方法。然后,在对应的映射文件中编写对应的Sql语句。
- 使用mybatis-plus的工程:不用写接口方法,不用写sql语句。首先,继承mybatis-plus提供的模板(通用)XxxMapper。然后,调用相应的crud方法即可。
- 原理:因为在启动类中加入了@MapperScan("com.atguigu.mapper")
,从而实现把指定包下面的所有的mapper接口所动态生成的代理类交给ioc容器来管理,所以在测试类中可以对ioc容器中管理的组件进行自动装配了,这里我们自动装配UserMapper这个Bean。 - 报错:private UserMapper userMapper;中的userMapper有红色波浪线。首先上面分析的(原理)是没有任何问题的。因为@MapperScan("com.atguigu.mapper")扫描的包下都是接口,但在ioc容器中只能存在类所对应的bean,不能存在接口所对应的bean,所以如上面所说是将mapper接口所动态生成的代理类交给ioc容器来管理。而在idea中,它认为UserMapper是一个接口,在idea的编译后半段,idea认为这是无法进行自动装配的,所以有红色波浪线。但注意,在运行接口是没有任何问题的。
- 运行报错:(355条消息) 【Java异常】idea 报错:无效的目标发行版:17 的解决办法_No8g攻城狮的博客-CSDN博客_无效的源发行版17
- selectList(Wrapper wrapper):Wrapper为条件构造器。也就是说当我们在查询数据时,如果我们有查询条件的话,我们就可以通过Wrapper来实现。如果没有条件的话,就写null。//selectList()根据MP内置的条件构造器查询一个list集合,null表示没有条件,即查询所有
- 报错:Unknown column 'id' in 'field list':表没有这个字段
-
第e步:问题分析
- 问题1:解决private UserMapper userMapper;中的userMapper有红色波浪线的问题,方法:在UserMapper.java中加入@Repository注解。@Repository注解的作用是将当前类或者接口标识为一个持久层组件。
- 问题2:整个过程中我们没有告诉mybaits要查询哪个表?那它是怎么有知道的呢?因为BaseMapper<User>中的泛型起了作用,User对应的就是user表。为什么会去查询id,name,email呢?因为泛型User中我们设置了属性id,name,email,所以有SELECT id,name,age,email FROM user。总结,mybatis操作的表和字段,是由实体类(泛型)中的类名和属性决定的。
- 问题3:mybatis-plus查询user表以后,就把表中对应字段的值,赋值给了我们实体类中相对应的属性。
- 第a步:实体类User.java:因为数据库中的表要和实体类做映射关系;
-
第6步:添加日志功能,查询mybatis-plus帮我们生成的sql语句
- log-impl: org.apache.ibatis.logging.stdout.StdOutImpl:使用默认的(自带)的就行。
- 第一步:mysql
-
增
-
BaseMapper.insert(user)
- 获取自动递增的id=14240358972034957。为什么这个自动递增的主键这么长(实体类属性Long类型,表字段bigint类型)?这个并不是我们所使用的自动递增的主键。那这个主键到底是怎么样生成的呢?首先,在mybaits-plus中默认使用雪花算法来生成id值。
-
生成sql语句:INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
- User.java对应的是表名user
- User.java中的id、name、age、email属性对应的是表的字段
-
BaseMapper.insert(user)
-
删
-
BaseMapper.deleteById(1475754982694199298L);
- 这里如果没有加L的话报错,因为1475754982694199298果断已经超过了int的范围,所以我们在后面加上一个L字,表示它是一个Long类型的数据。
-
BaseMapper.deleteByMap(map);
- //根据map集合中所设置的条件删除记录
//DELETE FROM user WHERE name = ? AND age = ?
- //根据map集合中所设置的条件删除记录
-
BaseMapper.deleteBatchIds(idList);
-
//通过多个id批量删除
List<Long> idList = Arrays.asList(1L, 2L, 3L);,因为id是Long(对应数据库中的bigint)类型的。
//DELETE FROM user WHERE id IN ( ? , ? , ? )
-
//通过多个id批量删除
-
BaseMapper.deleteById(1475754982694199298L);
-
改
-
BaseMapper.updateById(user);
- //UPDATE user SET name=?, age=? WHERE id=?。如果某个属性没有赋值,那么这表中的这个字段不会被更新。
-
BaseMapper.updateById(user);
-
查
-
BaseMapper.selectById(4L);
-
//SELECT id,name,age,email FROM user WHERE id=?。返回id=xxx用户信息。
-
-
BaseMapper.selectBatchIds(idList);
-
//根据多个id查询多个用户信息//SELECT id,name,age,email FROM user WHERE id IN ( ? , ? )
-
-
BaseMapper.selectByMap(map);
-
//通过map条件查询用户信息//SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
-
-
BaseMapper.selectList(null);
- //查询所有用户信息
//SELECT id,name,age,email FROM user
- //查询所有用户信息
-
BaseMapper.selectById(4L);
- 测试自定义功能、执行自定义sql
- 应用场景:BaseMapper中的基本方法无法满足我们的CRUD需求
- 场景1:mybaits-plus实现两个表的联合查询。
- 场景2:mybaits-plus执行自定义的sql语句。
- 原理:因为mybaits-plus是在mybatis的基础之上只做增强而不做改变,所以我们之前单独使用mybatis时怎么实现,现在我们就应该怎么实现。
- 功能"集合":mybatis
- "神的"冰箱:mybatis
- 详细步骤
- 回忆,单独使用mybatis的工程:
- 第一步:创建Mapper接口。
- 第二步:创建映射文件,在里面编写sql语句。
- 第一步:在已经有的Mapper接口:UserMapper.java(extends BaseMapper<User>),创建接口方法
- 第1步:声明接口方法:Map<String,Object> selectMapById(Long id)
- 完整的接口文件:
@Repository public interface UserMapper extends BaseMapper<User> { // 根据id查询用户信息,返回map集合 Map<String,Object> selectMapById(Long id); }
- 第二步:创建映射文件
- 写在哪里?application.yml中通过mybatis-plus.mapper-location=xxx进行配置,这个属性mybatis-plus已经给我们配置了一个默认的位置:classpath*:/mapper/**/*.xml(类路径下的,mapper目录下的,任意子目录下的,任意.xml文件,都是会被看成映射文件)。
- 自定义位置?如mybatis-plus.mapper-location=xxx
- 如何编写?
- 第1步:XxxMapper.xml名称要和UserMapper.java接口名称中Xxx=User。
- 第2步:namespace的值是UserMapper.java的绝对路径。
- 第3步:<select>标签
- 第a步:id="selectMapById(接口方法名称)"
- 第b步:resultType="map"。因为mybatis中有类型别名的说法,而这里的"map"就是mybatis(默认)自定义的HashMap集合的类型别名,所以我们这里直接写"map"即可。
- 第c步:编写sql语句。
- 完整映射文件?
<?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.atguigu.mapper.UserMapper"> <!--Map<String,Object> selectMapById(Long id)--> <select id="selectMapById" resultType="map"> select id,name ,age,email from user where id=#{id} </select> </mapper>
- 第三步:编写测试类
@Test public void selectMapById(){ Map<String, Object> map = userMapper.selectMapById(1L); System.out.println(map); }
- 回忆,单独使用mybatis的工程:
- 总结:
- 从这个案例大家也能够看出来,mybatis-plus其实就是mybtis的一个增强工具,mybatis-plus并不会去改mybatis原有的功能。
- 应用场景:BaseMapper中的基本方法无法满足我们的CRUD需求
2 通用service
- 概述
- 可以使用mybatis-plus提供的通用Mapper中的方法对表进行CRUD操作,同理也可以使用mybatis-plus提供的通用service中的方法对表进行CRUD操作。
- 通用service与通用Mapper的区别与联系
- 联系(官网):通用 Service CRUD 封装IService接口,进一步封装 CRUD ,而底层通过调用通用的Mapper实现CRUD。
- 区别(官网):方法名前缀:查(get/list)删(remove)分页(page)。
- 总结(CSDN):Mapper方式,可以实现简单的CRUD。Service方式,可以实现更加丰富的CRUD,但是必须依赖Mapper,也就是必须编写mapper接口。Service简直是BaseMapper的大扩充,不但包含了所有基本方法,还加入了很多批处理功能。
- IService的原理?同上
- 使用
- 方案
- 方案1:直接使用ServiceImpl<M extends BaseMapper<T>,T>。但不建议这样去用,因为以后所遇到的业务逻辑是非常复杂的,开发人员需要根据自己的需求来编写自已的业务逻辑代码,所以mybatis-plus提供的通用ServiceImpl一定是无法满足所有的业务逻辑的需求的。
- 方案2:参考UserMapper.java。可以自定义一个UserService,来继承通用ServiceImpl。这样即可以使用通用ServiceImpl提供的功能,也能够自定义自己的业务逻辑功能。
- 快速入门:自定义XxxServiceImpl
- 第一步:创建实体类User.java
- 第二步:创建自定义的Mapper:创建、注入、配置扫描
public interface UserMapper extends BaseMapper<User> { }
- 第三步:创建自定义Service接口:
public interface UserService extends IService<User> { }
- 第四步:创建自定义实现类:创建、注入
/** * ServiceImpl实现了IService,提供了IService中基础功能的实现 * 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,并在实现类中实现 */ @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { }
- 第五步:测试
- 测试1:long count = userService.count();,总记录数
- 测试2:userService.saveBatch(users);,批量添加(通用Mapper中就没有)
- 方案
3 常用注解
- @TableName
- 需求:User.java与t_user表映射
- 方案1:局部配置:@TableName
- 方案2:全局配置,application.yml,配置实体类对应的表的统一“前缀t_”:
# 配置MyBatis-Plus操作表的默认前缀table-prefix: t_
- @TableId
- 需求:表的主键必须取名为id,实体类的属性(主键)必须取名为id
- 方案:@TableId,实体类属性uid,表字段uid
- 属性1:value,实体类属性id,表字段uid
- 属性2:type,主键生成策略,mybatis-plus中主键id默认的生成策略是雪花算法
- 主键生成策略之雪花算法::type="IdType.none" 或 type="IdType.ACCESS_ID"
- 主键生成策略之mysql中的字段自动递增:type="IdType.AUTO"
- 注意:不管在哪个主键生成策略下,如果在调用save方法时Entity设置(set)了主键id,那么mybatis-plus就不会用任何主键生成策略,而直接使用Entity设置(set)的主键值。
- 通过全局配置配置主键生成策略
- 需求:统一指定主键生成策略
- 方案:application.yml
# 配置MyBatis-Plus的主键策略id-type: auto
-
雪花算法
-
应用场景:
-
场景1:非常适合使用在分布式架构的项目中
- 因为:它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。
-
-
- @TableField
- 需求:
- 方案:
- @TableLogic
- 业务:
- 需求:
4 条件构造(器):构造需要满足的条件
5 通用枚举
三 插件
1 分页插件(内置)
2 乐观锁插件
四 mybatisX插件(idea快速开发插件)
五 多数据源
六 代码生成器(内置)
1 mybatis逆向工程
- 自动生成
- 实体类
- mapper接口
- 映射文件
2 mybatis-plus代码生成器
- 自动生成(各个组件)
- 控制层
- 业务层
- mapper接口
- 映射文件
- 实体类