文章目录
- 一、概述
- 二、快速入门
- 2.1 数据库准备
- 2.2 创建springboot工程
- 2.3 实体类准备
- 2.4 测试MybatisPlus
- 三、MP常用配置
- 3.1 设置表映射规则
- 3.2 设置主键生成策略
- 3.3 设置字段映射关系
- 3.4 设置字段和列名的驼峰映射
- 3.5 日志
- 四、基本使用
- 4.1 增加(插入)
- 4.2 删除
- 4.3 修改
- 五、条件构造器Wrapper
- 5.1 概述
- 5.2 常用的AbstractWrapper方法
- 5.3 常用的QueryWrapper方法
- 5.4 常用UpdateWrapper方法
- 5.5 Lambda条件构造器
- 六、自定义Sql
- 6.1 准备数据库环境
- 6.2 创建实体类
- 6.3 Mybatis方式
- 6.4 Mybatis方式结合条件构造器
🌕博客x主页:己不由心王道长🌕!
🌎文章说明:MybatisPlus🌎
✅系列专栏:Mybatis续集
🌴本篇内容:对JDK8的新特性进行学习和讲解🌴
☕️每日一语:只要你奔跑,这个世界就会跟着你奔跑,只要你停驻,这个世界就会舍弃你独自奔跑。唯有你确定一个方向,使劲的跑起来,这个世界会为你而让路。早安,新的一天。☕️
🚩 交流社区:己不由心王道长(优质编程社区)
一、概述
MybatisPlus是一款Mybatis增强工具,用于简化开发,提高效率。 它在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
官网地址
二、快速入门
2.1 数据库准备
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`user_name` varchar(20) NOT NULL COMMENT '用户名',
`password` varchar(20) NOT NULL COMMENT '密码',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`address` varchar(100) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
加入数据:
insert into `user`(`id`,`user_name`,`password`,`name`,`age`,`address`) values (1,'wangye','123','王也',12,'北京'),(2,'zhugeqing','1332','诸葛青',13,'汉中'),(3,'zhangzhulan','123','张楚岚',22,'蘑菇石'),(4,'fengbaobao','1222','冯宝宝',221,'Chinese');
2.2 创建springboot工程
一、创建工程:
二、导入依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.daozhang</groupId>
<artifactId>MybatisPlus</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>MybatisPlus</name>
<description>MybatisPlus</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.6.13</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.6.13</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
</dependencies>
</project>
2.3 实体类准备
package com.daozhang.mybatisplus.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author Administrator
* @Date 2023/7/2 16:00
* @description 用户测试实体类
* @Version 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String address;
}
2.4 测试MybatisPlus
一、添加MybatisPlus依赖:
SpringBoot整合其他框架的第一步就是添加相关依赖:
<!--MybatisPlus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<!--Mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
添加配置信息:
肯定是要操作数据库的:
spring:
datasource:
url: jdbc:mysql://localhost:3306/mybatisplus?characterEncoding=utf-8&serverTimezone=UTC
username: root
password: 775033
driver-class-name: com.mysql.cj.jdbc.Driver
三、创建mapper并基础BaseMapper接口
package com.daozhang.mybatisplus.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.daozhang.mybatisplus.entity.User;
/**
* @Author Administrator
* @Date 2023/7/2 16:27
* @description 用户mapper层
* @Version 1.0
*/
public interface UserMapper extends BaseMapper<User> {
}
四、添加mapper层扫描:
五、测试:
/**
* @Author Administrator
* @Date 2023/7/2 16:30
* @description usermapper层测试类
* @Version 1.0
*/
@SpringBootTest
public class UserMapperTest {
@Autowired
UserMapper userMapper;
@Test
void selectList(){
List<User> users = userMapper.selectList(null);
Stream.of(users)
.forEach(System.out::println);
}
}
结果:
[User(id=1, userName=wangye, password=123, name=王也, age=12, address=北京),
User(id=2, userName=zhugeqing, password=1332, name=诸葛青, age=13, address=汉中),
User(id=3, userName=zhangzhulan, password=123, name=张楚岚, age=22, address=蘑菇石),
User(id=4, userName=fengbaobao, password=1222, name=冯宝宝, age=221, address=Chinese)]
三、MP常用配置
3.1 设置表映射规则
在默认情况下MP操作的表名是实体类的类名,但是如果表名和类名不一致就需要我们自己设置映射规则:可以分为单独设置和全局设置
一、单表设置:
如果表名是tb_user,而实体类名是User则可以使用以下写法。
二、全局设置表名前缀
试着想一下,如果大量数据库的表名与实体类不一样,我们一个一个去设置,是不是太麻烦了?是的,我们的解决办法是,在配置文件种设置全局表名前缀
如果一个项目中所有的表名相比于类名都是多了个前缀: tb_
。这可以使用如下方式配置
mybatis-plus:
global-config:
db-config:
#表名前缀
table-prefix: tb_
3.2 设置主键生成策略
问题分析:我们先做一个测试
可以看到数据库中id是顺序的:
@Test
void insertUser(){
User user = new User();
user.setUserName("麦当");
user.setPassword("22222");
int insert = userMapper.insert(user);
}
新加一个数据,问题是什么呢?
问题在于主键,我们希望的是主键根据数据库的主键自增,但是并没有,所以这里我们需要设置主键的自增策略,在这里的策略是使用mp的策略,使用的算法是雪花算法:
一、单独测试:
如果我们需要使用别的策略可以在定义实体类时,在代表主键的字段上加上@TableId
注解,使用其type
属性指定主键生成策略。如:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String address;
全部主键策略定义在了枚举类IdType
中,IdType
有如下的取值
-
AUTO
数据库ID自增,依赖于数据库。该类型请确保数据库设置了 ID自增 否则无效
-
NONE
未设置主键类型。若在代码中没有手动设置主键,则会根据主键的全局策略自动生成(默认的主键全局策略是基于雪花算法的自增ID)
-
INPUT
需要手动设置主键,若不设置。插入操作生成SQL语句时,主键这一列的值会是
null
。 -
ASSIGN_ID
当没有手动设置主键,即实体类中的主键属性为空时,才会自动填充,使用雪花算法
-
ASSIGN_UUID
当实体类的主键属性为空时,才会自动填充,使用UUID
二、全局设置:
mybatis-plus:
global-config:
db-config:
# id生成策略 auto为数据库自增
id-type: auto
3.3 设置字段映射关系
默认情况下MP会根据实体类的属性名去映射表的列名。
如果数据库的列表和实体类的属性名不一致了我们可以使用@TableField
注解的value
属性去设置映射关系。
如:如果表中一个列名叫password,但是实体类的属性名为passwordDD,可以使用如下方式进行配置:
3.4 设置字段和列名的驼峰映射
默认情况下MP会开启字段名列名的驼峰映射, 即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射 。
怎么证明?如下:
在实体类的属性中有一个userName,数据库中对应的列名为user_name,我们更改一下数据库然后测试:
可以看到MP自动把对应的属性使用了驼峰命名。
如果需要关闭我们可以使用如下配置进行关闭。
mybatis-plus:
configuration:
#是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射
map-underscore-to-camel-case: false
3.5 日志
日志一直都是很重要的功能实现,可以记录我们的数据和操作,还可以在出错时及时差错:
如果需要打印MP操作对应的SQL语句等,可以配置日志输出。打印SQL语句可以判断我们写的SQL在哪步出现问题
配置方式如下:
mybatis-plus:
configuration:
# 日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
测试:
四、基本使用
基本使用,这里先介绍基本的增删改:
4.1 增加(插入)
@Test
void insertUser(){
User user = new User();
user.setUserName("麦当");
user.setPassword("22222");
int insert = userMapper.insert(user);
}
SQL语句:
结果:
4.2 删除
@Test
void deleteById(){
Long id = 1675425759138750468L;
int i = userMapper.deleteById(id);
}
SQL:
4.3 修改
@Test
void updateUser(){
User user = new User();
user.setId(1L);
user.setUserName("诸葛青");
int i = userMapper.updateById(user);
}
SQL:
五、条件构造器Wrapper
5.1 概述
我们在实际操作数据库的时候会涉及到很多的条件。所以MP为我们提供了一个功能强大的条件构造器 Wrapper
。使用它可以让我们非常方便的构造条件。
其继承体系如下:
在其子类AbstractWrapper
中提供了很多用于构造Where条件的方法。
AbstractWrapper
的子类QueryWrapper
则额外提供了用于针对Select语法的select
方法。可以用来设置查询哪些列。
AbstractWrapper
的子类UpdateWrapper
则额外提供了用于针对SET语法的set
方法。可以用来设置对哪些列进行更新。
5.2 常用的AbstractWrapper方法
eq:equals,等于
gt:greater than ,大于 >
ge:greater than or equals,大于等于≥
lt:less than,小于<
le:less than or equals,小于等于≤
between:相当于SQL中的BETWEEN
like:模糊匹配。like(“name”,“黄”),相当于SQL的name like ‘%黄%’
likeRight:模糊匹配右半边。likeRight(“name”,“黄”),相当于SQL的name like ‘黄%’
likeLeft:模糊匹配左半边。likeLeft(“name”,“黄”),相当于SQL的name like ‘%黄’
notLike:notLike(“name”,“黄”),相当于SQL的name not like ‘%黄%’
isNull
isNotNull
and:SQL连接符AND
or:SQL连接符OR
in: in(“age",{1,2,3})相当于 age in(1,2,3)
groupBy: groupBy(“id”,“name”)相当于 group by id,name
orderByAsc :orderByAsc(“id”,“name”)相当于 order by id ASC,name ASC
orderByDesc :orderByDesc (“id”,“name”)相当于 order by id DESC,name DESC
示例一:
@Test
void AbstractWrapperTest(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//设置查询年龄为12
queryWrapper.eq("age",12);
queryWrapper.eq("address","北京");
List<User> users = userMapper.selectList(queryWrapper);
Stream.of(users)
.forEach(System.out::println);
}
}
示例二:
@Test
void AbstractWrapperTest02(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//设置查询条件为age在12、13、18、20之中
queryWrapper.in("age",12,13,18,20);
//设置查询条件为id在1-10之间
queryWrapper.between("id",1,10);
//
queryWrapper.like("name","也");
List<User> users = userMapper.selectList(queryWrapper);
Stream.of(users)
.forEach(System.out::println);
}
示例三:
@Test
void AbstractWrapperTest03(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//设置查询条件为age在12、13、18、20之中
queryWrapper.in("id",1,2,3,4);
queryWrapper.gt("age",11);
queryWrapper.orderByAsc("age");
List<User> users = userMapper.selectList(queryWrapper);
Stream.of(users)
.forEach(System.out::println);
}
5.3 常用的QueryWrapper方法
QueryWrapper的 select 可以设置要查询的列。
示例一:
select(String… sqlSelect) 方法的测试为要查询的列名
@Test
void QueryWrapperTest01(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.select("age","name");
List<User> users = userMapper.selectList(userQueryWrapper);
Stream.of(users)
.forEach(System.out::println);
}
示例二、
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
方法的第一个参数为实体类的字节码对象,第二个参数为Predicate类型,可以使用lambda的写法,过滤要查询的字段 (主键除外) 。
@Test
void QueryWrapperTest02(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.select(User.class, new Predicate<TableFieldInfo>() {
@Override
public boolean test(TableFieldInfo tableFieldInfo) {
return "user_name".equals(tableFieldInfo.getColumn());
}
});
List<User> users = userMapper.selectList(userQueryWrapper);
Stream.of(users)
.forEach(System.out::println);
}
Lambda表达式写法:
@Test
void QueryWrapperTest02(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.select(User.class,q->{
return "user_name".equals(q.getColumn());
});
List<User> users = userMapper.selectList(userQueryWrapper);
Stream.of(users)
.forEach(System.out::println);
}
示例三:
select(Predicate<TableFieldInfo> predicate)
方法第一个参数为Predicate类型,可以使用lambda的写法,过滤要查询的字段 (主键除外) 。
@Test
void QueryWrapperTest03(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>(new User());
userQueryWrapper.select(new Predicate<TableFieldInfo>() {
@Override
public boolean test(TableFieldInfo tableFieldInfo) {
return "user_name".equals(tableFieldInfo.getColumn());
}
});
List<User> users = userMapper.selectList(userQueryWrapper);
Stream.of(users)
.forEach(System.out::println);
}
5.4 常用UpdateWrapper方法
我们前面在使用update方法时需要创建一个实体类对象传入,用来指定要更新的列及对应的值。但是如果需要更新的列比较少时,创建这么一个对象显的有点麻烦和复杂。
我们可以使用UpdateWrapper的set方法来设置要更新的列及其值。同时这种方式也可以使用Wrapper去指定更复杂的更新条件。
示例:
@Test
void UpdateWrapperTest01(){
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper.gt("age",12);
userUpdateWrapper.set("name","王也1");
int update = userMapper.update(null, userUpdateWrapper);
}
5.5 Lambda条件构造器
我们前面在使用条件构造器时列名都是用字符串的形式去指定。这种方式无法在编译期确定列名的合法性。
所以MP提供了一个Lambda条件构造器可以让我们直接以实体类的方法引用的形式来指定列名。这样就可以弥补上述缺陷。
@Test
void LambdaQueryWrapperTest(){
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.gt(User::getAge,12);
lambdaQueryWrapper.like(User::getUserName,"也");
List<User> users = userMapper.selectList(lambdaQueryWrapper);
Stream.of(users)
.forEach(System.out::println);
}
六、自定义Sql
虽然MP为我们提供了很多常用的方法,并且也提供了条件构造器。但是如果真的遇到了复制的SQL时,我们还是需要自己去定义方法,自己去写对应的SQL,这样SQL也更有利于后期维护。
因为MP是对mybatis做了增强,所以还是支持之前Mybatis的方式去自定义方法。
同时也支持在使用Mybatis的自定义方法时使用MP的条件构造器帮助我们进行条件构造。
6.1 准备数据库环境
CREATE TABLE `orders` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`price` int(11) DEFAULT NULL COMMENT '价格',
`remark` varchar(100) DEFAULT NULL COMMENT '备注',
`user_id` int(11) DEFAULT NULL COMMENT '用户id',
`update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`version` int(11) DEFAULT '1' COMMENT '版本',
`del_flag` int(1) DEFAULT '0' COMMENT '逻辑删除标识,0-未删除,1-已删除',
`create_by` varchar(100) DEFAULT NULL COMMENT '创建人',
`update_by` varchar(100) DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
/*Data for the table `orders` */
insert into `orders`(`id`,`price`,`remark`,`user_id`,`update_time`,`create_time`,`version`,`del_flag`,`create_by`,`update_by`) values (1,2000,'无',2,'2021-08-24 21:02:43','2021-08-24 21:02:46',1,0,NULL,NULL),(2,3000,'无',3,'2021-08-24 21:03:32','2021-08-24 21:03:35',1,0,NULL,NULL),(3,4000,'无',2,'2021-08-24 21:03:39','2021-08-24 21:03:41',1,0,NULL,NULL);
6.2 创建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Orders {
private Long id;
/**
* 价格
*/
private Integer price;
/**
* 备注
*/
private String remark;
/**
* 用户id
*/
private Integer userId;
/**
* 更新时间
*/
private LocalDateTime updateTime;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 版本
*/
private Integer version;
/**
* 逻辑删除标识,0-未删除,1-已删除
*/
private Integer delFlag;
}
6.3 Mybatis方式
一、定义方法:
User findBy(Long id);
二、先配置xml文件的存放目录
mapper-locations: classpath*:/mapper/**/*.xml
三、xml映射文件中编写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.daozhang.mybatisplus.mapper.UserMapper">
<select id="findBy" resultType="com.daozhang.mybatisplus.entity.User">
select * from user where id=#{id}
</select>
</mapper>
测试:
@Test
void FindByTest(){
User by = userMapper.findBy(1L);
Stream.of(by)
.forEach(System.out::println);
}
结果:
6.4 Mybatis方式结合条件构造器
我们在使用上述方式自定义方法时。如果也希望我们的自定义方法能像MP自带方法一样使用条件构造器来进行条件构造的话只需要使用如下方式即可。
①方法定义中添加Warpper类型的参数
添加Warpper类型的参数,并且要注意给其指定参数名。
User findUserByWrapper(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
②在SQL语句中获取Warpper拼接的SQL片段进行拼接。
<select id="findUserByWrapper" resultType="com.daozhang.mybatisplus.entity.User">
select * from user ${ew.customSqlSegment}
</select>
@Test
void findByWrapperTest(){
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(User::getAge,12);
User userByWrapper = userMapper.findUserByWrapper(lambdaQueryWrapper);
Stream.of(userByWrapper)
.forEach(System.out::println);
}