前言
MyBatis-Plus是一个个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。MyBatis-Plus提供了通用的mapper和service,可以在不编写任何SQL语句的情况下,快速的实现对单表的CRUD、批量、逻辑删除、分页等操作。
官网:https://baomidou.com/
哈喽,大家好,/我是有勇气的牛排/(全网同名)🐮🐮🐮
有问题的小伙伴欢迎在文末/评论,点赞、收藏/是对我最大的支持!!!。
官网:https://www.couragesteak.com/
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
支持数据库
任何能使用 MyBatis
进行 CRUD, 并且支持标准 SQL 的数据库,具体支持情况如下,如果不在下列表查看分页部分教程 PR 您的支持。
- MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb,informix,TDengine,redshift
- 达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库,优炫数据库
2 开发环境
JDK: JDK8+
构建工具:mavem
MySQL:5.7
Spring Boot
MyBatis-Plus:3.5.1
3 数据库准备
创建表
CREATE DATABASE `mybatis_plus` ;
use `mybatis_plus`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL COMMENT '主键ID',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
添加数据
INSERT INTO user (id, name, age, email) VALUES
(1, "有勇气的牛排1", 18, "test1@couragesteak.com"),
(2, "有勇气的牛排2", 19, "test2@couragesteak.com"),
(3, "有勇气的牛排3", 20, "test3@couragesteak.com"),
(4, "有勇气的牛排4", 21, "test4@couragesteak.com"),
(5, "有勇气的牛排5", 22, "test5@couragesteak.com");

4 BaseMapper 接口
4.1 案例 selectList
pojo/entity:UserEntity
@Data
public class UserEntity {
private Long id;
private String name;
private Integer age;
private String email;
}
mapper:UserMapper.java(接口)
@Repository
public interface UserMapper extends BaseMapper<UserEntity> {
}
Controller:TestController.java
@RestController
public class TestController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/test")
public String testSelectList(){
List<User> list = userMapper.selectList(null);
list.forEach(System.out::println);
return "666";
}
}
测试方法==Controller
package com.couragesteak;
import com.couragesteak.mapper.UserMapper;
import com.couragesteak.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class MyBatisPlusTest {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList(){
System.out.println("666");
List<User> list = userMapper.selectList(null);
list.forEach(System.out::println);
}
}

4.2 插入方法 insert
@Test
public void testInsert() {
User user = new User();
user.setName("有勇气的牛排6");
user.setAge(18);
user.setEmail("test6@couragesteak.com");
int result = userMapper.insert(user);
System.out.println(result);
System.out.println("result: " + result);
System.out.println("result: " + user.getId());
}
4.3 删除方法 delete
4.3.1 deleteById
删除id=1637055722611748866
的用户
DELETE FROM user WHERE id=?
int result = userMapper.deleteById(1637055722611748866L);
System.out.println("result: " + result);
4.3.2 deleteBatchIds 批量删除
DELETE FROM user WHERE id IN ( ? , ? , ? )
List<Long> list = Arrays.asList(1L, 2L, 3L);
int result = userMapper.deleteBatchIds(list);
System.out.println("result: " + result);
4.3.3 deleteByMap 按照条件删除
DELETE FROM user WHERE name = ? AND age = ?
Map<String, Object> map = new HashMap<>();
map.put("name", "有勇气的牛排6");
map.put("age", 22);
int result = userMapper.deleteByMap(map);
System.out.println("result: " + result);
4.4 update 修改信息
UPDATE user SET name=?, email=? WHERE id=?
User user = new User();
user.setId(8L);
user.setName("牛排哥");
user.setEmail("test1@couragesteak.com");
int result = userMapper.updateById(user);
System.out.println("result: " + result);

4.5 查询功能
4.5.1 selectById
通过id查询用户信息
SELECT id,name,age,email FROM user WHERE id=?
User user = userMapper.selectById(1L);
System.out.println(user);

4.5.2 selectBatchIds 批量查询
SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )
List<Long> list = Arrays.asList(1L, 2L, 3L);
List<User> users = userMapper.selectBatchIds(list);
users.forEach(System.out::println);

4.5.3 selectByMap 条件查询
SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
Map<String, Object> map = new HashMap<>();
map.put("name", "牛排哥");
map.put("age", 18);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);

4.5.4 selectList
SELECT id,name,age,email FROM user
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
4.6 MyBatis 自定义Mapper查询方法
时间久了还真会忘,下面一起回顾下
创建映射
classpath: mapper/UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.couragesteak.mapper.UserMapper">
<select id="selectByMapId" resultType="map">
select id,name,age,email from user where id = #{id}
</select>
</mapper>
UserMapper.java
接口
@Repository
public interface UserMapper extends BaseMapper<User> {
Map<String, Object> selectByMapId(Long id);
}
调用
@SpringBootTest
public class MyBatisPlusTest {
@Autowired
private UserMapper userMapper;
@Test
public void testSelect() {
Map<String, Object> map = userMapper.selectByMapId(1L);
System.out.println(map);
}
}

5 Service CRUD接口
5.1 创建自己的Service
这里我们通过继承 MyBatisPlus的IService,来实现我们自己的Serice
com.couragesteak.service
: sercice接口
package com.couragesteak.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.couragesteak.pojo.User;
public interface UserService extends IService<User> {
}
com.couragesteak.service.Impl
: sercice接口实现类
package com.couragesteak.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.couragesteak.mapper.UserMapper;
import com.couragesteak.pojo.User;
import com.couragesteak.service.UserService;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

5.2 save添加
5.2.1 saveBatch 批量添加
ArrayList<User> list = new ArrayList<>();
for (int i = 0; i <= 10; i++) {
User user = new User();
user.setName("有勇气的牛排" + i);
user.setAge(18 + i);
list.add(user);
}
boolean b = userService.saveBatch(list);
System.out.println(b);
6 常用注解
6.1 @TableName 指定表
在上文的实际测试中,我们通过MyBatis-Plus实现了基本的CRUD,并没有指定要操作的表,仅仅在Mapper接口继承BaseMapper时,设置了泛型User,而操作的表为user表。
由此,我们可以得出,MyBatis-Plus在确定操作的表时,通过BaseMapper的泛型决定,即实体类型决定,并且默认操作表名和实体类名一致。
@TableName("c_user")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
6.2 全局配置指定表前缀
如果表前缀统一,通过配置此操作,可以省去6.1节中,为每个表添加@TableName注解。
mybatis-plus:
global-config:
db-config:
table-prefix: "c_"
6.3 @Tableld
6.3.1 主键配置
MyBatis-Plus在实现CRUD时,会默认将id作为主键,并且在插入数据时,默认基于雪花算法的策略生成id。
public class User {
@TableId
private Long uid;
private String name;
}
@TableId注解的value属性,用于指定主键的字段
public class User {
@TableId(value = "uid")
private Long id;
private String name;
}
type类型有:
AUTO(0)
: 数据库ID自增(确保数据库设置自增)
NONE(1)
: 用户输入ID
INPUT(2)
: 分配ID
ASSIGN_ID(3)
(默认): 分配ID(主键类型为number/string): 雪花算法(与数据库是否自增无关)
ASSIGN_UUID(4)
: 分配ID(主键类型为string): 分配UUID
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
}
6.3.2 雪花算法
雪花算发是由Twitter公布的分布式主键生成算法,它能保证不同表的主键的不同性,以及相同表的主键有序性。
1. 核心思想
(1)长度攻64bit(一个long型)
(2)首先是一个符号位,1bit标识,由于long基本类型在Java时带符号的,最好位是符号位,整数是0,负数是1,所以id一般为正数,最高位是0。
(3)41bit时间戳(毫秒级),存储的时间是时间戳的差值(当前时间戳-开始时间戳),结果约等于69.73年。
(4)10bit作为机器id(5bit是数据中心,5bit是机器的id,可以部署在1024个节点)
(5)12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生1024个节点)

2. 优点
整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率高。
6.4 @TableFild 指定属性对应字段名
(1)MyBatis-Plus在执行SQL语句时,要保证实体类中的属性名和表中的字段包吃包一致。
(2)情景一:如果不一致,MyBatis-Plus会将 驼峰命名与下划线命名自动转换。
(3)情景二,如果情景一不成立,则需要使用 @TableFild(“表字段名”)来设置对应字段。
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField("u_name")
private String name;
}
6.5 @TableLogic 逻辑删除
物理删除:真实删除,将对应数据从数据中删除。
逻辑删除:假删除,将对应数据中代表是否删除状态的字段,标记为删除状态。
应用场景:可以进行数据恢复。
实体类
@TableName("c_user")
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField("u_name")
private String name;
private Integer age;
private String email;
@TableLogic
private Integer isDeleted;
}
开启逻辑删除后,delete将会变为update
List<Long> list = Arrays.asList(1L, 2L, 3L);
int result = userMapper.deleteBatchIds(list);
System.out.println("result: " + result);
查询语句也会发生变化
List<User> list = userMapper.selectList(null);
list.forEach(System.out::println);
7 条件构造器
7.1 QueryWrapper
7.1.1 组装查询条件
场景:查询用户名包含9,年龄在18~20,邮箱部位null的用户信息
@Test
public void test01() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("u_name", "9")
.between("age", 18, 22)
.isNotNull("email");
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}

7.1.2 组装排序条件
场景:查询用户信息,按照年龄降序,若年龄相同,则按照id升序排序
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age")
.orderByAsc("id");
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);

7.1.3 组装删除
删除邮箱地址为null的用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("email");
int result = userMapper.delete(queryWrapper);
System.out.println("result:" + result);
7.1.4 and/or 条件优先级
将 (age>20 且 u_name 包含9) 或 email=null 的用户信息修改
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 18)
.like("u_name", "9")
.or()
.isNull("email");
User user = new User();
user.setName("牛排哥");
int result = userMapper.update(user, queryWrapper);
System.out.println("result: " + result);
将 u_name包含9,且(age>20 或 email=null)的用户信息修改
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("u_name","9")
.and(i->i.gt("age",18).or().isNull("email"));
User user = new User();
user.setName("有勇气的牛排博客");
int result = userMapper.update(user, queryWrapper);
System.out.println("result: " + result);
7.1.5 组装select 设置要查询的字段
查询 用户名、年龄、邮箱
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("u_name", "age", "email");
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
maps.forEach(System.out::println);

7.1.6 实现子查询
查询 id<=3 的用户信息
# 子查询案例
select * from user
where id in(
select uid from user where id <=3
)
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("id","select id from c_user where id <= 3");
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
7.2 UpdateWrapper 设置条件、字段
UpdateWrapper 不仅可以设置条件,还可以设置字段
场景:将 u_name包含9,且(age>18 或 email=null)的用户信息修改
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.like("u_name", "9")
.and(i -> i.gt("age", 18).or().isNull("email"));
updateWrapper.set("u_name", "牛排哥").set("email", "my@couragesteak.com");
int result = userMapper.update(null, updateWrapper);
System.out.println("result: " + result);
7.3 condition
在开发中,组装条件是最常见的功能,而这些条件数据来源于用户,是可选的,因此我们需要判断这些条件,若没有选择则不需要组装,以免影响SQL结果。
动态SQL,(这种组并不好)
String username = "";
Integer ageBegin = 20;
Integer ageEnd = 30;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(username)) {
queryWrapper.like("u_name", username);
}
if (ageBegin != null) {
queryWrapper.ge("age", 18);
}
if (ageEnd != null) {
queryWrapper.le("age", 18);
}
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
通过condition判断,将会很大程度上简化代码
String username = "9";
Integer ageBegin = 18;
Integer ageEnd = 30;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like(StringUtils.isNotBlank(username), "u_name", username)
.ge(ageBegin != null, "age", ageBegin)
.le(ageEnd != null, "age", ageEnd);
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);

但是,为了避免字段写错,因此可以使用 LambdaQueryWrapper
7.4 LambdaQueryWrapper 可访问实体字段, 避免写错
String username = "9";
Integer ageBegin = 18;
Integer ageEnd = 30;
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.isNotBlank(username), User::getName, username)
.ge(ageBegin != null, User::getAge, ageBegin)
.le(ageEnd != null, User::getAge, ageEnd);
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
7.5 LambdaUpdateWrapper
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.like(User::getName, "9")
.and(i -> i.gt(User::getAge, 18).or().isNull(User::getEmail));
updateWrapper.set(User::getName, "牛排哥").set(User::getEmail, "my@couragesteak.com");
int result = userMapper.update(null, updateWrapper);
System.out.println("result: " + result);
8 插件
8.1 分页插件
配置类: MyBatisPlusConfig.java
package com.couragesteak.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.couragesteak.mapper")
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
测试
Page<User> page = new Page<>(2, 3);
userMapper.selectPage(page, null);
System.out.println(page);
System.out.println("======");
System.out.println(page.getRecords());
System.out.println("当前页面: " + page.getCurrent());
System.out.println("当前 查询 记录数: " + page.getSize());
System.out.println("总页数: " + page.getPages());
System.out.println("获取总记录数: " + page.getTotal());
System.out.println("是否有下一页: " + page.hasNext());
System.out.println("是否有上一页: " + page.hasPrevious());

8.2 xml 自定义分页
场景:查询 age > 20的用户信息,并且分页
yml
mybatis-plus:
type-aliases-package: com.couragesteak.pojo
UserMapper.java
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.couragesteak.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.Map;
@Repository
public interface UserMapper extends BaseMapper<User> {
Map<String, Object> selectByMapId(Long id);
Page<User> selectPageVo(@Param("page") Page<User> page, @Param("page") Integer age);
}
UserMapper.xml
<select id="selectPageVo" resultType="User">
select id,u_name,age,email from c_user where age > #{age}
</select>
测试
Page<User> page = new Page<>(1, 3);
userMapper.selectPageVo(page, 20);
System.out.println(page);
System.out.println("======");
System.out.println(page.getRecords());
System.out.println("当前页面: " + page.getCurrent());
System.out.println("当前 查询 记录数: " + page.getSize());
System.out.println("总页数: " + page.getPages());
System.out.println("获取总记录数: " + page.getTotal());
System.out.println("是否有下一页: " + page.hasNext());
System.out.println("是否有上一页: " + page.hasPrevious());

8.3 乐观锁插件
8.3.1 模拟数据修改冲突
创建表
use mybatis_plus;
CREATE TABLE `c_product` (
`id` bigint(20) NOT NULL COMMENT '主键ID',
`name` varchar(30) DEFAULT NULL COMMENT '商品名称',
`price` int(11) DEFAULT 0 COMMENT '价格',
`version` int(50) DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
插入数据
INSERT INTO c_product (id, NAME, price) VALUES (1, '网站开发', 2000);
创建实体
@Data
public class Product {
private Long id;
private String name;
private Integer price;
private Integer version;
}
案例: 某商品售价100,先加50,再减30,但是小王、小李同时读取数据库,进行修改,导致小李修改的结果被小王的覆盖成为70。(应为120)
Product product_li = productMapper.selectById(1);
Product product_w = productMapper.selectById(1);
System.out.println("小李查询的商品价格:" + product_li.getPrice());
System.out.println("小李查询的商品价格:" + product_w.getPrice());
product_li.setPrice(product_li.getPrice() + 50);
productMapper.updateById(product_li);
product_w.setPrice(product_w.getPrice() - 30);
productMapper.updateById(product_w);
Product product_boss = productMapper.selectById(1);
System.out.println("老板查询的商品价格:" + product_boss.getPrice());
8.3.2 乐观锁实现流程
在表中添加 version 字段,取出记录时获取当前version。
SELECT id,`name`,price,`version` FROM c_product WHERE id=1
更新时,version+1,如果where语句中的version版本不对,则更新失败。
UPDATE c_product SET price=price+50, `version`=`version`+1 WHERE id=1 AND
`version`=1
8.3.3 MyBatis-Plus实现乐观锁
1、修改实体类
package com.couragesteak.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
@Data
@TableName("c_product")
public class Product {
private Long id;
private String name;
private Integer price;
@Version
private Integer version;
}
2、添加乐观锁插件配置
package com.couragesteak.config;
...
@Configuration
@MapperScan("com.couragesteak.mapper")
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
3、下面可以执行8.3.1中的案例,进行测试
4、优化流程 :失败重试
Product product_li = productMapper.selectById(1);
Product product_w = productMapper.selectById(1);
System.out.println("小李查询的商品价格:" + product_li.getPrice());
System.out.println("小李查询的商品价格:" + product_w.getPrice());
product_li.setPrice(product_li.getPrice() + 50);
productMapper.updateById(product_li);
product_w.setPrice(product_w.getPrice() - 30);
int result = productMapper.updateById(product_w);
if (result==0){
Product productNew = productMapper.selectById(1);
productNew.setPrice(productNew.getPrice()-30);
productMapper.updateById(productNew);
}
Product product_boss = productMapper.selectById(1);
System.out.println("老板查询的商品价格:" + product_boss.getPrice());
9 通用枚举
表中有些字段值是固定的,例如性别(男或女),此时我们可以使用MaBatis-Plus的通用枚举来实现。

yaml
mybatis-plus:
type-enums-package: com.couragesteak.enums
枚举类: SexEnum.java
@Getter
public enum SexEnum {
MALE(1,"男"),
FEMALE(2,"女");
private Integer sex;
private String sexName;
SexEnum(Integer sex, String sexName) {
this.sex = sex;
this.sexName = sexName;
}
}
实体
@Data
@TableName("c_user")
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField("u_name")
private String name;
private Integer age;
private String email;
@EnumValue
private SexEnum sex;
@TableLogic
private Integer isDeleted;
}
解决报错:
报错: Cause: java.sql.SQLException: Incorrect integer value: 'MALE' for column 'sex' at row 1
show variables like '%char%';
set character_set_server=utf8mb4;
ALTER TABLE `c_user` MODIFY COLUMN `sex` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
10 代码生成器
依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
快速生成代码: FastAutoGeneratorTest.java
package com.couragesteak;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;
public class FastAutoGeneratorTest {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false", "root", "root123456")
.globalConfig(builder -> {
builder.author("有勇气的牛排")
.enableSwagger()
.fileOverride()
.outputDir("E://java//MyBatisPlus//tmp");
})
.packageConfig(builder -> {
builder.parent("com.couragesteak")
.moduleName("mybatisplus")
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "E://java//MyBatisPlus//tmp"));
})
.strategyConfig(builder -> {
builder.addInclude("c_user")
.addTablePrefix("t_", "c_");
})
.templateEngine(new FreemarkerTemplateEngine())
.execute();
}
}
12 多数据源
适用于多种场景:纯粹多库、读写分离、一主多从、混合模式等。
创建两个库:mybatis_plus、mybatis_plu_1(新建),将mybatis_plus库的product表移动到mybatis_plu_1库,通过一个测试用例,分别获取用户数据商品数据,如果获取到说明,多库模拟成功。
引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
yml配置
spring:
datasource:
dynamic:
primary: master
strict: false
datasource:
master:
url: jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root123456
slave_1:
url: jdbc:mysql://localhost:3306/mybatis_plus_1?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root123456
指定数据源,可以是实体,也可以是Service
UserServiceImpl实现类
@Service
@DS("master")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
ProductServiceImpl 实现类
@Service
@DS("slave_1")
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
}
13 MyBatisX插件
idea安装插件:MyBatisX
官方文档:https://baomidou.com/pages/ba5b24/#功能

13.1 生成实体、mapper、service、映射文件
需要连接数据源



13.2 生成 insert语句
生成MyBatisSQL



13.3 生成delete语句
插入

删除
# 根据ID和用户名删除
deleteByIdAndName
int deleteByIdAndName(@Param("id") Long id, @Param("name") String name);
<delete id="deleteByIdAndName">
delete
from c_product
where id = #{id,jdbcType=NUMERIC}
AND name = #{name,jdbcType=VARCHAR}
</delete>
这也太厉害这
查询
selectAllOrderByAgeDesc
[1] 感谢尚硅谷
<h2><a id="_0"></a>前言</h2>
<p>MyBatis-Plus是一个个MyBatis的<strong>增强工具</strong>,在MyBatis的基础上只做增强不做改变,为<strong>简化开发</strong>、<strong>提高效率而生</strong>。MyBatis-Plus提供了通用的mapper和service,可以在不编写任何SQL语句的情况下,快速的实现对单表的CRUD、批量、逻辑删除、分页等操作。</p>
<p>官网:https://baomidou.com/</p>
<p><font face="楷体,华文行楷,隶书,黑体" color="red" size="4"><strong>哈喽,大家好,/我是有勇气的牛排/(全网同名)🐮🐮🐮</strong></font></p>
<p><font face="楷体,华文行楷,隶书,黑体" color="blue" size="4"><strong>有问题的小伙伴欢迎在文末/评论,点赞、收藏/是对我最大的支持!!!。</strong></font></p>
<p>官网:<a href="https://www.couragesteak.com/" target="_blank">https://www.couragesteak.com/</a></p>
<h3><a id="_14"></a>特性</h3>
<ul>
<li><strong>无侵入</strong>:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑</li>
<li><strong>损耗小</strong>:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作</li>
<li><strong>强大的 CRUD 操作</strong>:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求</li>
<li><strong>支持 Lambda 形式调用</strong>:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错</li>
<li><strong>支持主键自动生成</strong>:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题</li>
<li><strong>支持 ActiveRecord 模式</strong>:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作</li>
<li><strong>支持自定义全局通用操作</strong>:支持全局通用方法注入( Write once, use anywhere )</li>
<li><strong>内置代码生成器</strong>:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用</li>
<li><strong>内置分页插件</strong>:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询</li>
<li><strong>分页插件支持多种数据库</strong>:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库</li>
<li><strong>内置性能分析插件</strong>:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询</li>
<li><strong>内置全局拦截插件</strong>:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作</li>
</ul>
<h3><a id="_29"></a>支持数据库</h3>
<blockquote>
<p>任何能使用 <code>MyBatis</code> 进行 CRUD, 并且支持标准 SQL 的数据库,具体支持情况如下,如果不在下列表查看分页部分教程 PR 您的支持。</p>
</blockquote>
<ul>
<li>MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb,informix,TDengine,redshift</li>
<li>达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库,优炫数据库</li>
</ul>
<h2><a id="2__38"></a>2 开发环境</h2>
<p>JDK: JDK8+</p>
<p>构建工具:mavem</p>
<p>MySQL:5.7</p>
<p>Spring Boot</p>
<p>MyBatis-Plus:3.5.1</p>
<h2><a id="3__52"></a>3 数据库准备</h2>
<p>创建表</p>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">CREATE</span> DATABASE `mybatis_plus` <span class="hljs-comment">/*!40100 DEFAULT CHARACTER SET utf8mb4 */</span>;
use `mybatis_plus`;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `<span class="hljs-keyword">user</span>` (
`id` <span class="hljs-type">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">'主键ID'</span>,
`name` <span class="hljs-type">varchar</span>(<span class="hljs-number">30</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">'姓名'</span>,
`age` <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">'年龄'</span>,
`email` <span class="hljs-type">varchar</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">'邮箱'</span>,
<span class="hljs-keyword">PRIMARY</span> KEY (`id`)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8;
</code></div></pre>
<p>添加数据</p>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">user</span> (id, name, age, email) <span class="hljs-keyword">VALUES</span>
(<span class="hljs-number">1</span>, "有勇气的牛排1", <span class="hljs-number">18</span>, "test1@couragesteak.com"),
(<span class="hljs-number">2</span>, "有勇气的牛排2", <span class="hljs-number">19</span>, "test2@couragesteak.com"),
(<span class="hljs-number">3</span>, "有勇气的牛排3", <span class="hljs-number">20</span>, "test3@couragesteak.com"),
(<span class="hljs-number">4</span>, "有勇气的牛排4", <span class="hljs-number">21</span>, "test4@couragesteak.com"),
(<span class="hljs-number">5</span>, "有勇气的牛排5", <span class="hljs-number">22</span>, "test5@couragesteak.com");
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/df2d72ac9ab10dcb4f67b4299d21e063.png" alt="image.png" /></p>
<h2><a id="4_BaseMapper__85"></a>4 BaseMapper 接口</h2>
<h3><a id="41___selectList_87"></a>4.1 案例 selectList</h3>
<p>pojo/entity:UserEntity</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Data</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserEntity</span> {
<span class="hljs-keyword">private</span> Long id; <span class="hljs-comment">// 默认为雪花算法</span>
<span class="hljs-keyword">private</span> String name;
<span class="hljs-keyword">private</span> Integer age;
<span class="hljs-keyword">private</span> String email;
}
</code></div></pre>
<p>mapper:UserMapper.java(接口)</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 继承 MyBatis-Plus的 BaseMapper<泛型></span>
<span class="hljs-meta">@Repository</span> <span class="hljs-comment">// 将接口标识为持久层组件</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">UserMapper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">BaseMapper</span><UserEntity> {
}
</code></div></pre>
<p>Controller:TestController.java</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TestController</span> {
<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span> UserMapper userMapper;
<span class="hljs-comment">// http://127.0.0.1:8080/test</span>
<span class="hljs-meta">@RequestMapping("/test")</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">testSelectList</span><span class="hljs-params">()</span>{
<span class="hljs-comment">// 通过条件构造器,查询一个list集合,若没有条件,则可以设置null为参数</span>
List<User> list = userMapper.selectList(<span class="hljs-literal">null</span>);
list.forEach(System.out::println);
<span class="hljs-keyword">return</span> <span class="hljs-string">"666"</span>;
}
}
</code></div></pre>
<p>测试方法==Controller</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">/*
* @Author : 有勇气的牛排(全网同名)
* @FileName: MyBatisPlusTest.java
* desc :
* */</span>
<span class="hljs-keyword">package</span> com.couragesteak;
<span class="hljs-keyword">import</span> com.couragesteak.mapper.UserMapper;
<span class="hljs-keyword">import</span> com.couragesteak.pojo.User;
<span class="hljs-keyword">import</span> org.junit.jupiter.api.Test;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.boot.test.context.SpringBootTest;
<span class="hljs-keyword">import</span> java.util.List;
<span class="hljs-meta">@SpringBootTest</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MyBatisPlusTest</span> {
<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span> UserMapper userMapper;
<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testSelectList</span><span class="hljs-params">()</span>{
System.out.println(<span class="hljs-string">"666"</span>);
<span class="hljs-comment">// 通过条件构造器,查询一个list集合,若没有条件,则可以设置null为参数</span>
List<User> list = userMapper.selectList(<span class="hljs-literal">null</span>);
list.forEach(System.out::println);
}
}
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/68d4f2f305343a1930bc25406a3c2d49.png" alt="image.png" /></p>
<h3><a id="42__insert_178"></a>4.2 插入方法 insert</h3>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testInsert</span><span class="hljs-params">()</span> {
<span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
<span class="hljs-comment">// user.setId(6);</span>
user.setName(<span class="hljs-string">"有勇气的牛排6"</span>);
user.setAge(<span class="hljs-number">18</span>);
user.setEmail(<span class="hljs-string">"test6@couragesteak.com"</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.insert(user);
System.out.println(result);
System.out.println(<span class="hljs-string">"result: "</span> + result);
System.out.println(<span class="hljs-string">"result: "</span> + user.getId());
}
</code></div></pre>
<h3><a id="43__delete_198"></a>4.3 删除方法 delete</h3>
<h4><a id="431_deleteById_200"></a>4.3.1 deleteById</h4>
<p>删除<code>id=1637055722611748866</code>的用户</p>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">WHERE</span> id<span class="hljs-operator">=</span>?
</code></div></pre>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 通过id删除用户信息</span>
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.deleteById(<span class="hljs-number">1637055722611748866L</span>);
System.out.println(<span class="hljs-string">"result: "</span> + result);
</code></div></pre>
<h4><a id="432_deleteBatchIds__214"></a>4.3.2 deleteBatchIds 批量删除</h4>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">WHERE</span> id <span class="hljs-keyword">IN</span> ( ? , ? , ? )
</code></div></pre>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 通过多个id实现批量删除</span>
List<Long> list = Arrays.asList(<span class="hljs-number">1L</span>, <span class="hljs-number">2L</span>, <span class="hljs-number">3L</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.deleteBatchIds(list);
System.out.println(<span class="hljs-string">"result: "</span> + result);
</code></div></pre>
<h4><a id="433_deleteByMap__227"></a>4.3.3 deleteByMap 按照条件删除</h4>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">WHERE</span> name <span class="hljs-operator">=</span> ? <span class="hljs-keyword">AND</span> age <span class="hljs-operator">=</span> ?
</code></div></pre>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 根据map集合中所设置的条件删除用户信息</span>
Map<String, Object> map = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span><>();
map.put(<span class="hljs-string">"name"</span>, <span class="hljs-string">"有勇气的牛排6"</span>);
map.put(<span class="hljs-string">"age"</span>, <span class="hljs-number">22</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.deleteByMap(map);
System.out.println(<span class="hljs-string">"result: "</span> + result);
</code></div></pre>
<h3><a id="44_update__243"></a>4.4 update 修改信息</h3>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">UPDATE</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">SET</span> name<span class="hljs-operator">=</span>?, email<span class="hljs-operator">=</span>? <span class="hljs-keyword">WHERE</span> id<span class="hljs-operator">=</span>?
</code></div></pre>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 修改用户信息</span>
<span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
user.setId(<span class="hljs-number">8L</span>);
user.setName(<span class="hljs-string">"牛排哥"</span>);
user.setEmail(<span class="hljs-string">"test1@couragesteak.com"</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.updateById(user);
System.out.println(<span class="hljs-string">"result: "</span> + result);
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/1df1c25f3063eb463c3f52138d8c6f3f.png" alt="image.png" /></p>
<h3><a id="45__262"></a>4.5 查询功能</h3>
<h4><a id="451_selectById_264"></a>4.5.1 selectById</h4>
<p>通过id查询用户信息</p>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">SELECT</span> id,name,age,email <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">WHERE</span> id<span class="hljs-operator">=</span>?
</code></div></pre>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 通过id查询用户信息</span>
<span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> userMapper.selectById(<span class="hljs-number">1L</span>);
System.out.println(user);
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/5ce5013ab83c2271703f58e252d4f129.png" alt="image.png" /></p>
<h4><a id="452_selectBatchIds__280"></a>4.5.2 selectBatchIds 批量查询</h4>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">SELECT</span> id,name,age,email <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">WHERE</span> id <span class="hljs-keyword">IN</span> ( ? , ? , ? )
</code></div></pre>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 根据多个id查询多个用户信息</span>
List<Long> list = Arrays.asList(<span class="hljs-number">1L</span>, <span class="hljs-number">2L</span>, <span class="hljs-number">3L</span>);
List<User> users = userMapper.selectBatchIds(list);
users.forEach(System.out::println);
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/b559e534b0ca018f5fec6db28c77dc48.png" alt="image.png" /></p>
<h4><a id="453_selectByMap__295"></a>4.5.3 selectByMap 条件查询</h4>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">SELECT</span> id,name,age,email <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">WHERE</span> name <span class="hljs-operator">=</span> ? <span class="hljs-keyword">AND</span> age <span class="hljs-operator">=</span> ?
</code></div></pre>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 根据map集合中的条件查询用户信息</span>
Map<String, Object> map = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span><>();
map.put(<span class="hljs-string">"name"</span>, <span class="hljs-string">"牛排哥"</span>);
map.put(<span class="hljs-string">"age"</span>, <span class="hljs-number">18</span>);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/8887b2dd741218ba53ec779e1231895f.png" alt="image.png" /></p>
<h4><a id="454_selectList_312"></a>4.5.4 selectList</h4>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">SELECT</span> id,name,age,email <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span>
</code></div></pre>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 查询所有数据</span>
<span class="hljs-comment">// SELECT id,name,age,email FROM user</span>
List<User> users = userMapper.selectList(<span class="hljs-literal">null</span>);
users.forEach(System.out::println);
</code></div></pre>
<h3><a id="46_MyBatis_Mapper_325"></a>4.6 MyBatis 自定义Mapper查询方法</h3>
<p>时间久了还真会忘,下面一起回顾下</p>
<p>创建映射</p>
<p><code>classpath: mapper/UserMapper.xml</code></p>
<pre><div class="hljs"><code class="lang-xml"><span class="hljs-meta"><?xml version="1.0" encoding="UTF-8" ?></span>
<span class="hljs-meta"><!DOCTYPE <span class="hljs-keyword">mapper</span>
<span class="hljs-keyword">PUBLIC</span> <span class="hljs-string">"-//mybatis.org//DTD Mapper 3.0//EN"</span>
<span class="hljs-string">"https://mybatis.org/dtd/mybatis-3-mapper.dtd"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">mapper</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"com.couragesteak.mapper.UserMapper"</span>></span>
<span class="hljs-comment"><!-- Map<String, Object> selectMapById(Long id); --></span>
<span class="hljs-tag"><<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"selectByMapId"</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">"map"</span>></span>
select id,name,age,email from user where id = #{id}
<span class="hljs-tag"></<span class="hljs-name">select</span>></span>
<span class="hljs-tag"></<span class="hljs-name">mapper</span>></span>
</code></div></pre>
<p><code>UserMapper.java</code> 接口</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 继承 MyBatis-Plus的 BaseMapper<泛型></span>
<span class="hljs-meta">@Repository</span> <span class="hljs-comment">// 将接口标识为持久层组件</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">UserMapper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">BaseMapper</span><User> {
<span class="hljs-comment">/**
* 自定义查询: 根据id查询用户信息为map集合
* 映射文件: classpath: mapper/UserMapper.xml
* <span class="hljs-doctag">@param</span> id
* <span class="hljs-doctag">@return</span>
*/</span>
Map<String, Object> <span class="hljs-title function_">selectByMapId</span><span class="hljs-params">(Long id)</span>;
}
</code></div></pre>
<p>调用</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@SpringBootTest</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MyBatisPlusTest</span> {
<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span> UserMapper userMapper;
<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testSelect</span><span class="hljs-params">()</span> {
<span class="hljs-comment">// 自定义查询方法</span>
Map<String, Object> map = userMapper.selectByMapId(<span class="hljs-number">1L</span>);
System.out.println(map);
}
}
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/d355983e063e64de041d6fa5a805eb41.png" alt="image.png" /></p>
<h2><a id="5_Service_CRUD_389"></a>5 Service CRUD接口</h2>
<h3><a id="51_Service_391"></a>5.1 创建自己的Service</h3>
<p>这里我们通过继承 MyBatisPlus的IService,来实现我们自己的Serice</p>
<p><code>com.couragesteak.service</code>: sercice接口</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-keyword">package</span> com.couragesteak.service;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.extension.service.IService;
<span class="hljs-keyword">import</span> com.couragesteak.pojo.User;
<span class="hljs-comment">/**
* UserService 继承 IService 模板提供的基础功能
* IServcice<泛型为-实体类对象>
*/</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">UserService</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">IService</span><User> {
}
</code></div></pre>
<p><code>com.couragesteak.service.Impl</code>: sercice接口实现类</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">/*
* @Author : 有勇气的牛排(全网同名)
* @FileName: UserServiceImpl.java
* desc : Service实现类
* */</span>
<span class="hljs-keyword">package</span> com.couragesteak.service.impl;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
<span class="hljs-keyword">import</span> com.couragesteak.mapper.UserMapper;
<span class="hljs-keyword">import</span> com.couragesteak.pojo.User;
<span class="hljs-keyword">import</span> com.couragesteak.service.UserService;
<span class="hljs-comment">/**
* 1. 继承 ServiceImpl<M:当前接口类型, T:当前实体类型>
* 2. 实现自己的接口 UserSercice
*/</span>
<span class="hljs-meta">@Service</span> <span class="hljs-comment">// 将Sercice标记为组件</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserServiceImpl</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">ServiceImpl</span><UserMapper, User> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">UserService</span> {
}
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/0a7cc88fddaa1bfe9c464c3cc496c699.png" alt="image.png" /></p>
<h3><a id="52_save_443"></a>5.2 save添加</h3>
<h4><a id="521_saveBatch__445"></a>5.2.1 saveBatch 批量添加</h4>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 批量添加:单个sql语句循环添加</span>
<span class="hljs-comment">// INSERT INTO user ( id, name, age ) VALUES ( ?, ?, ? )</span>
ArrayList<User> list = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span><>();
<span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <= <span class="hljs-number">10</span>; i++) {
<span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
user.setName(<span class="hljs-string">"有勇气的牛排"</span> + i);
user.setAge(<span class="hljs-number">18</span> + i);
list.add(user);
}
<span class="hljs-type">boolean</span> <span class="hljs-variable">b</span> <span class="hljs-operator">=</span> userService.saveBatch(list);
System.out.println(b);
</code></div></pre>
<h2><a id="6__466"></a>6 常用注解</h2>
<h3><a id="61_TableName__468"></a>6.1 @TableName 指定表</h3>
<p>在上文的实际测试中,我们通过MyBatis-Plus实现了基本的CRUD,并没有指定要操作的表,仅仅在Mapper接口继承BaseMapper时,设置了泛型User,而操作的表为user表。</p>
<p>由此,我们可以得出,MyBatis-Plus在确定操作的表时,通过BaseMapper的泛型决定,即实体类型决定,并且默认操作表名和实体类名一致。</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@TableName("c_user")</span> <span class="hljs-comment">// 设置实体类对应的表名</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> {
<span class="hljs-keyword">private</span> Long id;
<span class="hljs-keyword">private</span> String name;
<span class="hljs-keyword">private</span> Integer age;
<span class="hljs-keyword">private</span> String email;
}
</code></div></pre>
<h3><a id="62__484"></a>6.2 全局配置指定表前缀</h3>
<p>如果表前缀统一,通过配置此操作,可以省去6.1节中,为每个表添加@TableName注解。</p>
<pre><div class="hljs"><code class="lang-yaml"><span class="hljs-attr">mybatis-plus:</span>
<span class="hljs-comment"># 设置MyBatis-Plus的全局配置</span>
<span class="hljs-attr">global-config:</span>
<span class="hljs-attr">db-config:</span>
<span class="hljs-comment"># 设置实体类所对应的表的统一前缀</span>
<span class="hljs-attr">table-prefix:</span> <span class="hljs-string">"c_"</span>
</code></div></pre>
<h3><a id="63_Tableld_498"></a>6.3 @Tableld</h3>
<h4><a id="631__500"></a>6.3.1 主键配置</h4>
<p>MyBatis-Plus在实现CRUD时,会默认将id作为主键,并且在插入数据时,默认基于雪花算法的策略生成id。</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> {
<span class="hljs-comment">// 将属性对应的字段uid指定为主键</span>
<span class="hljs-meta">@TableId</span>
<span class="hljs-keyword">private</span> Long uid;
<span class="hljs-keyword">private</span> String name;
}
</code></div></pre>
<p>@TableId注解的value属性,用于指定主键的字段</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> {
<span class="hljs-comment">// 将属性id, 对应到表uid</span>
<span class="hljs-meta">@TableId(value = "uid")</span>
<span class="hljs-keyword">private</span> Long id;
<span class="hljs-keyword">private</span> String name;
}
</code></div></pre>
<p><strong>type类型有:</strong></p>
<p><code>AUTO(0)</code>: 数据库ID自增(确保数据库设置自增)<br />
<code>NONE(1)</code>: 用户输入ID<br />
<code>INPUT(2)</code>: 分配ID<br />
<code>ASSIGN_ID(3)</code>(默认): 分配ID(主键类型为number/string): 雪花算法(与数据库是否自增无关)<br />
<code>ASSIGN_UUID(4)</code>: 分配ID(主键类型为string): 分配UUID</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> {
<span class="hljs-comment">// @TableId的value属性,用于设置主键的字段</span>
<span class="hljs-comment">// @TableId的type属性,用于设置主键生成策略</span>
<span class="hljs-meta">@TableId(value = "id", type = IdType.AUTO)</span>
<span class="hljs-keyword">private</span> Long id;
}
</code></div></pre>
<h4><a id="632__545"></a>6.3.2 雪花算法</h4>
<p>雪花算发是由Twitter公布的分布式主键生成算法,它能保证不同表的主键的不同性,以及相同表的主键有序性。</p>
<p><strong>1. 核心思想</strong></p>
<p>(1)长度攻64bit(一个long型)</p>
<p>(2)首先是一个符号位,1bit标识,由于long基本类型在Java时带符号的,最好位是符号位,整数是0,负数是1,所以id一般为正数,最高位是0。</p>
<p>(3)41bit时间戳(毫秒级),存储的时间是时间戳的差值(当前时间戳-开始时间戳),结果约等于69.73年。</p>
<p>(4)10bit作为机器id(5bit是数据中心,5bit是机器的id,可以部署在1024个节点)</p>
<p>(5)12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生1024个节点)</p>
<p><img src="https://static.couragesteak.com/article/932c3ccd45f77bb87a4d78f44ed7d2a3.png" alt="image.png" /></p>
<p><strong>2. 优点</strong></p>
<p>整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率高。</p>
<h3><a id="64_TableFild__573"></a>6.4 @TableFild 指定属性对应字段名</h3>
<p>(1)MyBatis-Plus在执行SQL语句时,要保证实体类中的属性名和表中的字段包吃包一致。</p>
<p>(2)情景一:如果不一致,MyBatis-Plus会将 驼峰命名与下划线命名自动转换。</p>
<p>(3)情景二,如果情景一不成立,则需要使用 @TableFild(“表字段名”)来设置对应字段。</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> {
<span class="hljs-comment">// @TableId的value属性,用于设置主键的字段</span>
<span class="hljs-comment">// @TableId的type属性,用于设置主键生成策略</span>
<span class="hljs-meta">@TableId(value = "id", type = IdType.AUTO)</span>
<span class="hljs-keyword">private</span> Long id;
<span class="hljs-comment">// 指定属性所对应的字段名</span>
<span class="hljs-meta">@TableField("u_name")</span>
<span class="hljs-keyword">private</span> String name;
}
</code></div></pre>
<h3><a id="65_TableLogic__594"></a>6.5 @TableLogic 逻辑删除</h3>
<p>物理删除:真实删除,将对应数据从数据中删除。</p>
<p>逻辑删除:假删除,将对应数据中代表是否删除状态的字段,标记为删除状态。</p>
<p>应用场景:可以进行数据恢复。</p>
<p>实体类</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@TableName("c_user")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> {
<span class="hljs-meta">@TableId(value = "id", type = IdType.AUTO)</span>
<span class="hljs-keyword">private</span> Long id;
<span class="hljs-meta">@TableField("u_name")</span>
<span class="hljs-keyword">private</span> String name;
<span class="hljs-keyword">private</span> Integer age;
<span class="hljs-keyword">private</span> String email;
<span class="hljs-comment">// 开启逻辑删除</span>
<span class="hljs-meta">@TableLogic</span>
<span class="hljs-keyword">private</span> Integer isDeleted;
}
</code></div></pre>
<p>开启逻辑删除后,delete将会变为update</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 通过多个id实现批量删除</span>
<span class="hljs-comment">// 未开启逻辑删除:DELETE FROM user WHERE id IN ( ? , ? , ? )</span>
<span class="hljs-comment">// 开启逻辑删除:UPDATE c_user SET is_deleted=1 WHERE id IN ( ? , ? , ? ) AND is_deleted=0</span>
List<Long> list = Arrays.asList(<span class="hljs-number">1L</span>, <span class="hljs-number">2L</span>, <span class="hljs-number">3L</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.deleteBatchIds(list);
System.out.println(<span class="hljs-string">"result: "</span> + result);
</code></div></pre>
<p>查询语句也会发生变化</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// SELECT id,u_name AS name,age,email,is_deleted FROM c_user WHERE is_deleted=0</span>
List<User> list = userMapper.selectList(<span class="hljs-literal">null</span>);
list.forEach(System.out::println);
</code></div></pre>
<h2><a id="7__645"></a>7 条件构造器</h2>
<h3><a id="71_QueryWrapper_647"></a>7.1 QueryWrapper</h3>
<h4><a id="711__649"></a>7.1.1 组装查询条件</h4>
<p>场景:查询用户名包含9,年龄在18~20,邮箱部位null的用户信息</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test01</span><span class="hljs-params">()</span> {
<span class="hljs-comment">// SELECT id,u_name AS name,age,email,is_deleted FROM c_user WHERE is_deleted=0 AND (u_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)</span>
QueryWrapper<User> queryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">QueryWrapper</span><>();
queryWrapper.like(<span class="hljs-string">"u_name"</span>, <span class="hljs-string">"9"</span>) <span class="hljs-comment">// (字段名, 值)</span>
.between(<span class="hljs-string">"age"</span>, <span class="hljs-number">18</span>, <span class="hljs-number">22</span>)
.isNotNull(<span class="hljs-string">"email"</span>);
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/ac1528fa391fc46bc8c5a217f1aa1b10.png" alt="image.png" /></p>
<h4><a id="712__668"></a>7.1.2 组装排序条件</h4>
<p>场景:查询用户信息,按照年龄降序,若年龄相同,则按照id升序排序</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// SELECT id,u_name AS name,age,email,is_deleted FROM c_user WHERE is_deleted=0 ORDER BY age DESC,id ASC</span>
QueryWrapper<User> queryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">QueryWrapper</span><>();
queryWrapper.orderByDesc(<span class="hljs-string">"age"</span>)
.orderByAsc(<span class="hljs-string">"id"</span>);
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/706ae544f1f3dac2a37bbf54654ce31b.png" alt="image.png" /></p>
<h4><a id="713__683"></a>7.1.3 组装删除</h4>
<p>删除邮箱地址为null的用户信息</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// UPDATE c_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)</span>
QueryWrapper<User> queryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">QueryWrapper</span><>();
queryWrapper.isNull(<span class="hljs-string">"email"</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.delete(queryWrapper);
System.out.println(<span class="hljs-string">"result:"</span> + result);
</code></div></pre>
<h4><a id="714_andor__695"></a>7.1.4 and/or 条件优先级</h4>
<p>将 (age>20 且 u_name 包含9) 或 email=null 的用户信息修改</p>
<pre><div class="hljs"><code class="lang-java">QueryWrapper<User> queryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">QueryWrapper</span><>();
queryWrapper.gt(<span class="hljs-string">"age"</span>, <span class="hljs-number">18</span>)
.like(<span class="hljs-string">"u_name"</span>, <span class="hljs-string">"9"</span>)
.or()
.isNull(<span class="hljs-string">"email"</span>);
<span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
user.setName(<span class="hljs-string">"牛排哥"</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.update(user, queryWrapper);
System.out.println(<span class="hljs-string">"result: "</span> + result);
</code></div></pre>
<p>将 u_name包含9,且(age>20 或 email=null)的用户信息修改</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 将 u_name包含9,且(age>18 或 email=null)的用户信息修改</span>
<span class="hljs-comment">// // UPDATE c_user SET u_name=? WHERE is_deleted=0 AND (u_name LIKE ? AND (age > ? OR email IS NULL))</span>
<span class="hljs-comment">// lambda中的条件优先执行</span>
QueryWrapper<User> queryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">QueryWrapper</span><>();
queryWrapper.like(<span class="hljs-string">"u_name"</span>,<span class="hljs-string">"9"</span>)
.and(i->i.gt(<span class="hljs-string">"age"</span>,<span class="hljs-number">18</span>).or().isNull(<span class="hljs-string">"email"</span>));
<span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
user.setName(<span class="hljs-string">"有勇气的牛排博客"</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.update(user, queryWrapper);
System.out.println(<span class="hljs-string">"result: "</span> + result);
</code></div></pre>
<h4><a id="715_select__729"></a>7.1.5 组装select 设置要查询的字段</h4>
<p>查询 用户名、年龄、邮箱</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// SELECT u_name,age,email FROM c_user WHERE is_deleted=0</span>
QueryWrapper<User> queryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">QueryWrapper</span><>();
queryWrapper.select(<span class="hljs-string">"u_name"</span>, <span class="hljs-string">"age"</span>, <span class="hljs-string">"email"</span>);
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
maps.forEach(System.out::println);
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/03a17472a305651e7b37e1ca52cbb6fd.png" alt="image.png" /></p>
<h4><a id="716__743"></a>7.1.6 实现子查询</h4>
<p>查询 id<=3 的用户信息</p>
<pre><div class="hljs"><code class="lang-sql"># 子查询案例
<span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> <span class="hljs-keyword">user</span>
<span class="hljs-keyword">where</span> id <span class="hljs-keyword">in</span>(
<span class="hljs-keyword">select</span> uid <span class="hljs-keyword">from</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">where</span> id <span class="hljs-operator"><=</span><span class="hljs-number">3</span>
)
</code></div></pre>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// SELECT id,u_name AS name,age,email,is_deleted FROM c_user WHERE is_deleted=0 AND (id IN (select id from c_user where id <= 3))</span>
QueryWrapper<User> queryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">QueryWrapper</span><>();
queryWrapper.inSql(<span class="hljs-string">"id"</span>,<span class="hljs-string">"select id from c_user where id <= 3"</span>);
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
</code></div></pre>
<h3><a id="72_UpdateWrapper__763"></a>7.2 UpdateWrapper 设置条件、字段</h3>
<p>UpdateWrapper 不仅可以设置条件,还可以设置字段</p>
<p>场景:将 u_name包含9,且(age>18 或 email=null)的用户信息修改</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// UPDATE c_user SET u_name=?,email=? WHERE is_deleted=0 AND (u_name LIKE ? AND (age > ? OR email IS NULL))</span>
UpdateWrapper<User> updateWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">UpdateWrapper</span><>();
<span class="hljs-comment">// 条件</span>
updateWrapper.like(<span class="hljs-string">"u_name"</span>, <span class="hljs-string">"9"</span>)
.and(i -> i.gt(<span class="hljs-string">"age"</span>, <span class="hljs-number">18</span>).or().isNull(<span class="hljs-string">"email"</span>));
<span class="hljs-comment">// 修改(相对于QueryWrapper,这里不在创建实体类对象)</span>
updateWrapper.set(<span class="hljs-string">"u_name"</span>, <span class="hljs-string">"牛排哥"</span>).set(<span class="hljs-string">"email"</span>, <span class="hljs-string">"my@couragesteak.com"</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.update(<span class="hljs-literal">null</span>, updateWrapper);
System.out.println(<span class="hljs-string">"result: "</span> + result);
</code></div></pre>
<h3><a id="73_condition_781"></a>7.3 condition</h3>
<p>在开发中,组装条件是最常见的功能,而这些条件数据来源于用户,是可选的,因此我们需要判断这些条件,若没有选择则不需要组装,以免影响SQL结果。</p>
<p>动态SQL,(这种组并不好)</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-type">String</span> <span class="hljs-variable">username</span> <span class="hljs-operator">=</span> <span class="hljs-string">""</span>;
<span class="hljs-type">Integer</span> <span class="hljs-variable">ageBegin</span> <span class="hljs-operator">=</span> <span class="hljs-number">20</span>;
<span class="hljs-type">Integer</span> <span class="hljs-variable">ageEnd</span> <span class="hljs-operator">=</span> <span class="hljs-number">30</span>;
<span class="hljs-comment">// SELECT id,u_name AS name,age,email,is_deleted FROM c_user WHERE is_deleted=0 AND (age >= ? AND age <= ?)</span>
QueryWrapper<User> queryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">QueryWrapper</span><>();
<span class="hljs-comment">// com.baomidou.mybatisplus.core.toolkit.StringUtils;</span>
<span class="hljs-keyword">if</span> (StringUtils.isNotBlank(username)) {
<span class="hljs-comment">// 判断某个字符串是否不为空、不为null、不为空白符</span>
queryWrapper.like(<span class="hljs-string">"u_name"</span>, username);
}
<span class="hljs-keyword">if</span> (ageBegin != <span class="hljs-literal">null</span>) {
queryWrapper.ge(<span class="hljs-string">"age"</span>, <span class="hljs-number">18</span>); <span class="hljs-comment">// ge 表示 >=</span>
}
<span class="hljs-keyword">if</span> (ageEnd != <span class="hljs-literal">null</span>) {
queryWrapper.le(<span class="hljs-string">"age"</span>, <span class="hljs-number">18</span>); <span class="hljs-comment">// le 表示 <=</span>
}
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
</code></div></pre>
<p>通过condition判断,将会很大程度上简化代码</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-type">String</span> <span class="hljs-variable">username</span> <span class="hljs-operator">=</span> <span class="hljs-string">"9"</span>;
<span class="hljs-type">Integer</span> <span class="hljs-variable">ageBegin</span> <span class="hljs-operator">=</span> <span class="hljs-number">18</span>;
<span class="hljs-type">Integer</span> <span class="hljs-variable">ageEnd</span> <span class="hljs-operator">=</span> <span class="hljs-number">30</span>;
<span class="hljs-comment">// SELECT id,u_name AS name,age,email,is_deleted FROM c_user WHERE is_deleted=0 AND (u_name LIKE ? AND age >= ? AND age <= ?)</span>
QueryWrapper<User> queryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">QueryWrapper</span><>();
queryWrapper.like(StringUtils.isNotBlank(username), <span class="hljs-string">"u_name"</span>, username)
.ge(ageBegin != <span class="hljs-literal">null</span>, <span class="hljs-string">"age"</span>, ageBegin)
.le(ageEnd != <span class="hljs-literal">null</span>, <span class="hljs-string">"age"</span>, ageEnd);
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/0452e2645accec021100d1a391c7cf7a.png" alt="image.png" /></p>
<p>但是,为了避免字段写错,因此可以使用 LambdaQueryWrapper</p>
<h3><a id="74_LambdaQueryWrapper___835"></a>7.4 LambdaQueryWrapper 可访问实体字段, 避免写错</h3>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-type">String</span> <span class="hljs-variable">username</span> <span class="hljs-operator">=</span> <span class="hljs-string">"9"</span>;
<span class="hljs-type">Integer</span> <span class="hljs-variable">ageBegin</span> <span class="hljs-operator">=</span> <span class="hljs-number">18</span>;
<span class="hljs-type">Integer</span> <span class="hljs-variable">ageEnd</span> <span class="hljs-operator">=</span> <span class="hljs-number">30</span>;
<span class="hljs-comment">// LambdaQueryWrapper<泛型为:实体类类型></span>
LambdaQueryWrapper<User> queryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">LambdaQueryWrapper</span><>();
queryWrapper.like(StringUtils.isNotBlank(username), User::getName, username)
.ge(ageBegin != <span class="hljs-literal">null</span>, User::getAge, ageBegin)
.le(ageEnd != <span class="hljs-literal">null</span>, User::getAge, ageEnd);
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
</code></div></pre>
<h3><a id="75_LambdaUpdateWrapper_854"></a>7.5 LambdaUpdateWrapper</h3>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// UPDATE c_user SET u_name=?,email=? WHERE is_deleted=0 AND (u_name LIKE ? AND (age > ? OR email IS NULL))</span>
LambdaUpdateWrapper<User> updateWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">LambdaUpdateWrapper</span><>();
<span class="hljs-comment">// 条件</span>
updateWrapper.like(User::getName, <span class="hljs-string">"9"</span>)
.and(i -> i.gt(User::getAge, <span class="hljs-number">18</span>).or().isNull(User::getEmail));
<span class="hljs-comment">// 修改(相对于QueryWrapper,这里不在创建实体类对象)</span>
updateWrapper.set(User::getName, <span class="hljs-string">"牛排哥"</span>).set(User::getEmail, <span class="hljs-string">"my@couragesteak.com"</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> userMapper.update(<span class="hljs-literal">null</span>, updateWrapper);
System.out.println(<span class="hljs-string">"result: "</span> + result);
</code></div></pre>
<h2><a id="8__870"></a>8 插件</h2>
<h3><a id="81__872"></a>8.1 分页插件</h3>
<p>配置类: MyBatisPlusConfig.java</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">/*
* @Author : 有勇气的牛排(全网同名)
* @FileName: MyBatisPlusConfig.java
* desc :
* */</span>
<span class="hljs-keyword">package</span> com.couragesteak.config;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.annotation.DbType;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
<span class="hljs-keyword">import</span> org.mybatis.spring.annotation.MapperScan;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@MapperScan("com.couragesteak.mapper")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MyBatisPlusConfig</span> {
<span class="hljs-meta">@Bean</span>
<span class="hljs-keyword">public</span> MybatisPlusInterceptor <span class="hljs-title function_">mybatisPlusInterceptor</span><span class="hljs-params">()</span>{
<span class="hljs-type">MybatisPlusInterceptor</span> <span class="hljs-variable">interceptor</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">MybatisPlusInterceptor</span>();
<span class="hljs-comment">// 添加具体插件: 分页插件</span>
interceptor.addInnerInterceptor(<span class="hljs-keyword">new</span> <span class="hljs-title class_">PaginationInnerInterceptor</span>(DbType.MYSQL));
<span class="hljs-keyword">return</span> interceptor;
}
}
</code></div></pre>
<p>测试</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// SELECT id,u_name AS name,age,email,is_deleted FROM c_user WHERE is_deleted=0 LIMIT ?,?</span>
Page<User> page = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Page</span><>(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>);
userMapper.selectPage(page, <span class="hljs-literal">null</span>);
System.out.println(page);
System.out.println(<span class="hljs-string">"======"</span>);
System.out.println(page.getRecords());
System.out.println(<span class="hljs-string">"当前页面: "</span> + page.getCurrent()); <span class="hljs-comment">// 当前页面</span>
System.out.println(<span class="hljs-string">"当前 查询 记录数: "</span> + page.getSize()); <span class="hljs-comment">// 查询 记录数</span>
System.out.println(<span class="hljs-string">"总页数: "</span> + page.getPages()); <span class="hljs-comment">// 总页数</span>
System.out.println(<span class="hljs-string">"获取总记录数: "</span> + page.getTotal()); <span class="hljs-comment">// 获取总记录数</span>
System.out.println(<span class="hljs-string">"是否有下一页: "</span> + page.hasNext()); <span class="hljs-comment">// 是否有下一页</span>
System.out.println(<span class="hljs-string">"是否有上一页: "</span> + page.hasPrevious()); <span class="hljs-comment">// 是否有上一页</span>
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/dd70140233e1c00310f66466a1cee9f7.png" alt="image.png" /></p>
<h3><a id="82_xml__931"></a>8.2 xml 自定义分页</h3>
<p>场景:查询 age > 20的用户信息,并且分页</p>
<p>yml</p>
<pre><div class="hljs"><code class="lang-yaml"><span class="hljs-attr">mybatis-plus:</span>
<span class="hljs-comment"># 配置类型别名所对应的包</span>
<span class="hljs-attr">type-aliases-package:</span> <span class="hljs-string">com.couragesteak.pojo</span>
</code></div></pre>
<p>UserMapper.java</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-keyword">import</span> com.baomidou.mybatisplus.core.mapper.BaseMapper;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.extension.plugins.pagination.Page;
<span class="hljs-keyword">import</span> com.couragesteak.pojo.User;
<span class="hljs-keyword">import</span> org.apache.ibatis.annotations.Param;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Repository;
<span class="hljs-keyword">import</span> java.util.Map;
<span class="hljs-meta">@Repository</span> <span class="hljs-comment">// 将接口标识为持久层组件</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">UserMapper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">BaseMapper</span><User> {
Map<String, Object> <span class="hljs-title function_">selectByMapId</span><span class="hljs-params">(Long id)</span>;
<span class="hljs-comment">// 自定义分页 返回值 必须为Page对象</span>
Page<User> <span class="hljs-title function_">selectPageVo</span><span class="hljs-params">(<span class="hljs-meta">@Param("page")</span> Page<User> page, <span class="hljs-meta">@Param("page")</span> Integer age)</span>;
}
</code></div></pre>
<p>UserMapper.xml</p>
<pre><div class="hljs"><code class="lang-xml"><span class="hljs-comment"><!-- Page<User> selectPageVo(@Param("page") Page<User> page, @Param("page") Integer age); --></span>
<span class="hljs-tag"><<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"selectPageVo"</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">"User"</span>></span>
select id,u_name,age,email from c_user where age > #{age}
<span class="hljs-tag"></<span class="hljs-name">select</span>></span>
</code></div></pre>
<p>测试</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// select id,u_name,age,email from c_user where age > ? LIMIT ?</span>
Page<User> page = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Page</span><>(<span class="hljs-number">1</span>, <span class="hljs-number">3</span>);
<span class="hljs-comment">// 查 age> 20 的,并且分页</span>
userMapper.selectPageVo(page, <span class="hljs-number">20</span>);
System.out.println(page);
System.out.println(<span class="hljs-string">"======"</span>);
System.out.println(page.getRecords());
System.out.println(<span class="hljs-string">"当前页面: "</span> + page.getCurrent()); <span class="hljs-comment">// 当前页面</span>
System.out.println(<span class="hljs-string">"当前 查询 记录数: "</span> + page.getSize()); <span class="hljs-comment">// 查询 记录数</span>
System.out.println(<span class="hljs-string">"总页数: "</span> + page.getPages()); <span class="hljs-comment">// 总页数</span>
System.out.println(<span class="hljs-string">"获取总记录数: "</span> + page.getTotal()); <span class="hljs-comment">// 获取总记录数</span>
System.out.println(<span class="hljs-string">"是否有下一页: "</span> + page.hasNext()); <span class="hljs-comment">// 是否有下一页</span>
System.out.println(<span class="hljs-string">"是否有上一页: "</span> + page.hasPrevious()); <span class="hljs-comment">// 是否有上一页</span>
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/a38b6c6e5f415973fc7186ae772a8d2f.png" alt="image.png" /></p>
<h3><a id="83__995"></a>8.3 乐观锁插件</h3>
<h4><a id="831__997"></a>8.3.1 模拟数据修改冲突</h4>
<p>创建表</p>
<pre><div class="hljs"><code class="lang-sql">use mybatis_plus;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `c_product` (
`id` <span class="hljs-type">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">'主键ID'</span>,
`name` <span class="hljs-type">varchar</span>(<span class="hljs-number">30</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">'商品名称'</span>,
`price` <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">'价格'</span>,
`version` <span class="hljs-type">int</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">'乐观锁版本号'</span>,
<span class="hljs-keyword">PRIMARY</span> KEY (`id`)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8;
</code></div></pre>
<p>插入数据</p>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> c_product (id, NAME, price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'网站开发'</span>, <span class="hljs-number">2000</span>);
</code></div></pre>
<p>创建实体</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Data</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Product</span> {
<span class="hljs-keyword">private</span> Long id;
<span class="hljs-keyword">private</span> String name;
<span class="hljs-keyword">private</span> Integer price;
<span class="hljs-keyword">private</span> Integer version;
}
</code></div></pre>
<p>案例: 某商品售价100,先加50,再减30,但是小王、小李同时读取数据库,进行修改,导致小李修改的结果被小王的覆盖成为70。(应为120)</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 小李 查询 商品价格</span>
<span class="hljs-type">Product</span> <span class="hljs-variable">product_li</span> <span class="hljs-operator">=</span> productMapper.selectById(<span class="hljs-number">1</span>);
<span class="hljs-comment">// 小王 查询 商品价格</span>
<span class="hljs-type">Product</span> <span class="hljs-variable">product_w</span> <span class="hljs-operator">=</span> productMapper.selectById(<span class="hljs-number">1</span>);
System.out.println(<span class="hljs-string">"小李查询的商品价格:"</span> + product_li.getPrice());
<span class="hljs-comment">// 小李查询的商品价格: 2000</span>
System.out.println(<span class="hljs-string">"小李查询的商品价格:"</span> + product_w.getPrice());
<span class="hljs-comment">// 小王查询的商品价格: 2000</span>
<span class="hljs-comment">// 小李将商品价格 +50</span>
product_li.setPrice(product_li.getPrice() + <span class="hljs-number">50</span>);
productMapper.updateById(product_li);
<span class="hljs-comment">// 小王将商品价格 -30</span>
product_w.setPrice(product_w.getPrice() - <span class="hljs-number">30</span>);
productMapper.updateById(product_w);
<span class="hljs-comment">// 老板查询商品价格</span>
<span class="hljs-type">Product</span> <span class="hljs-variable">product_boss</span> <span class="hljs-operator">=</span> productMapper.selectById(<span class="hljs-number">1</span>);
System.out.println(<span class="hljs-string">"老板查询的商品价格:"</span> + product_boss.getPrice());
<span class="hljs-comment">// 老板查询的商品价格:70</span>
</code></div></pre>
<h4><a id="832__1061"></a>8.3.2 乐观锁实现流程</h4>
<p>在表中添加 version 字段,取出记录时获取当前version。</p>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">SELECT</span> id,`name`,price,`version` <span class="hljs-keyword">FROM</span> c_product <span class="hljs-keyword">WHERE</span> id<span class="hljs-operator">=</span><span class="hljs-number">1</span>
</code></div></pre>
<p>更新时,version+1,如果where语句中的version版本不对,则更新失败。</p>
<pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">UPDATE</span> c_product <span class="hljs-keyword">SET</span> price<span class="hljs-operator">=</span>price<span class="hljs-operator">+</span><span class="hljs-number">50</span>, `version`<span class="hljs-operator">=</span>`version`<span class="hljs-operator">+</span><span class="hljs-number">1</span> <span class="hljs-keyword">WHERE</span> id<span class="hljs-operator">=</span><span class="hljs-number">1</span> <span class="hljs-keyword">AND</span>
`version`<span class="hljs-operator">=</span><span class="hljs-number">1</span>
</code></div></pre>
<h4><a id="833_MyBatisPlus_1078"></a>8.3.3 MyBatis-Plus实现乐观锁</h4>
<p>1、修改实体类</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">/*
* @Author : 有勇气的牛排(全网同名)
* @FileName: Product.java
* desc : 乐观锁版本
* */</span>
<span class="hljs-keyword">package</span> com.couragesteak.pojo;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.annotation.TableName;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.annotation.Version;
<span class="hljs-keyword">import</span> lombok.Data;
<span class="hljs-meta">@Data</span>
<span class="hljs-meta">@TableName("c_product")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Product</span> {
<span class="hljs-keyword">private</span> Long id;
<span class="hljs-keyword">private</span> String name;
<span class="hljs-keyword">private</span> Integer price;
<span class="hljs-meta">@Version</span> <span class="hljs-comment">// 标识乐观锁版本号字段</span>
<span class="hljs-keyword">private</span> Integer version;
}
</code></div></pre>
<p>2、添加乐观锁插件配置</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">/*
* @Author : 有勇气的牛排(全网同名)
* @FileName: MyBatisPlusConfig.java
* desc : 插件配置
* */</span>
<span class="hljs-keyword">package</span> com.couragesteak.config;
...
<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@MapperScan("com.couragesteak.mapper")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MyBatisPlusConfig</span> {
<span class="hljs-meta">@Bean</span>
<span class="hljs-keyword">public</span> MybatisPlusInterceptor <span class="hljs-title function_">mybatisPlusInterceptor</span><span class="hljs-params">()</span>{
<span class="hljs-type">MybatisPlusInterceptor</span> <span class="hljs-variable">interceptor</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">MybatisPlusInterceptor</span>();
<span class="hljs-comment">// 添加具体插件: 分页插件</span>
interceptor.addInnerInterceptor(<span class="hljs-keyword">new</span> <span class="hljs-title class_">PaginationInnerInterceptor</span>(DbType.MYSQL));
<span class="hljs-comment">// 添加乐观锁插件</span>
interceptor.addInnerInterceptor(<span class="hljs-keyword">new</span> <span class="hljs-title class_">OptimisticLockerInnerInterceptor</span>());
<span class="hljs-keyword">return</span> interceptor;
}
}
</code></div></pre>
<p>3、下面可以执行8.3.1中的案例,进行测试</p>
<p>4、优化流程 :失败重试</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 小李 查询 商品价格</span>
<span class="hljs-type">Product</span> <span class="hljs-variable">product_li</span> <span class="hljs-operator">=</span> productMapper.selectById(<span class="hljs-number">1</span>);
<span class="hljs-comment">// 小王 查询 商品价格</span>
<span class="hljs-type">Product</span> <span class="hljs-variable">product_w</span> <span class="hljs-operator">=</span> productMapper.selectById(<span class="hljs-number">1</span>);
System.out.println(<span class="hljs-string">"小李查询的商品价格:"</span> + product_li.getPrice());
<span class="hljs-comment">// 小李查询的商品价格: 2000</span>
System.out.println(<span class="hljs-string">"小李查询的商品价格:"</span> + product_w.getPrice());
<span class="hljs-comment">// 小王查询的商品价格: 2000</span>
<span class="hljs-comment">// 小李将商品价格 +50</span>
product_li.setPrice(product_li.getPrice() + <span class="hljs-number">50</span>);
productMapper.updateById(product_li);
<span class="hljs-comment">// 小王将商品价格 -30</span>
product_w.setPrice(product_w.getPrice() - <span class="hljs-number">30</span>);
<span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> productMapper.updateById(product_w);
<span class="hljs-keyword">if</span> (result==<span class="hljs-number">0</span>){
<span class="hljs-comment">// 操作失败,重试</span>
<span class="hljs-type">Product</span> <span class="hljs-variable">productNew</span> <span class="hljs-operator">=</span> productMapper.selectById(<span class="hljs-number">1</span>);
productNew.setPrice(productNew.getPrice()-<span class="hljs-number">30</span>);
productMapper.updateById(productNew);
}
<span class="hljs-comment">// 老板查询商品价格</span>
<span class="hljs-type">Product</span> <span class="hljs-variable">product_boss</span> <span class="hljs-operator">=</span> productMapper.selectById(<span class="hljs-number">1</span>);
System.out.println(<span class="hljs-string">"老板查询的商品价格:"</span> + product_boss.getPrice());
<span class="hljs-comment">// 老板查询的商品价格:120</span>
</code></div></pre>
<h2><a id="9__1177"></a>9 通用枚举</h2>
<p>表中有些字段值是固定的,例如性别(男或女),此时我们可以使用MaBatis-Plus的通用枚举来实现。</p>
<p><img src="https://static.couragesteak.com/article/32d5c3c329412d6f5621a34670571ca7.png" alt="image.png" /></p>
<p>yaml</p>
<pre><div class="hljs"><code class="lang-yaml"><span class="hljs-attr">mybatis-plus:</span>
<span class="hljs-comment"># 扫描通用枚举的包</span>
<span class="hljs-attr">type-enums-package:</span> <span class="hljs-string">com.couragesteak.enums</span>
</code></div></pre>
<p>枚举类: SexEnum.java</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Getter</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">enum</span> <span class="hljs-title class_">SexEnum</span> {
MALE(<span class="hljs-number">1</span>,<span class="hljs-string">"男"</span>),
FEMALE(<span class="hljs-number">2</span>,<span class="hljs-string">"女"</span>);
<span class="hljs-keyword">private</span> Integer sex;
<span class="hljs-keyword">private</span> String sexName;
<span class="hljs-comment">// 创建构造器</span>
SexEnum(Integer sex, String sexName) {
<span class="hljs-built_in">this</span>.sex = sex;
<span class="hljs-built_in">this</span>.sexName = sexName;
}
}
</code></div></pre>
<p>实体</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Data</span>
<span class="hljs-meta">@TableName("c_user")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span> {
<span class="hljs-meta">@TableId(value = "id", type = IdType.AUTO)</span>
<span class="hljs-keyword">private</span> Long id;
<span class="hljs-meta">@TableField("u_name")</span>
<span class="hljs-keyword">private</span> String name;
<span class="hljs-keyword">private</span> Integer age;
<span class="hljs-keyword">private</span> String email;
<span class="hljs-meta">@EnumValue</span> <span class="hljs-comment">// 将注解所标识属性的值存储到数据库中</span>
<span class="hljs-keyword">private</span> SexEnum sex;
<span class="hljs-meta">@TableLogic</span>
<span class="hljs-keyword">private</span> Integer isDeleted;
}
</code></div></pre>
<p>解决报错:</p>
<pre><div class="hljs"><code class="lang-shell">报错: Cause: java.sql.SQLException: Incorrect integer value: 'MALE' for column 'sex' at row 1
show variables like '%char%';
set character_set_server=utf8mb4;
ALTER TABLE `c_user` MODIFY COLUMN `sex` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
</code></div></pre>
<h2><a id="10__1253"></a>10 代码生成器</h2>
<p>依赖</p>
<pre><div class="hljs"><code class="lang-xml"><span class="hljs-comment"><!-- MyBatis-Plus 代码生成器 --></span>
<span class="hljs-tag"><<span class="hljs-name">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>com.baomidou<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>mybatis-plus-generator<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">version</span>></span>3.5.1<span class="hljs-tag"></<span class="hljs-name">version</span>></span>
<span class="hljs-tag"></<span class="hljs-name">dependency</span>></span>
<span class="hljs-comment"><!-- freemarker模板 --></span>
<span class="hljs-tag"><<span class="hljs-name">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.freemarker<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>freemarker<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">version</span>></span>2.3.31<span class="hljs-tag"></<span class="hljs-name">version</span>></span>
<span class="hljs-tag"></<span class="hljs-name">dependency</span>></span>
</code></div></pre>
<p>快速生成代码: FastAutoGeneratorTest.java</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">/*
* @Author : 有勇气的牛排(全网同名)
* @FileName: FastAutoGeneratorTest.java
* desc :
* */</span>
<span class="hljs-keyword">package</span> com.couragesteak;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.generator.FastAutoGenerator;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.generator.config.OutputFile;
<span class="hljs-keyword">import</span> com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
<span class="hljs-keyword">import</span> java.util.Collections;
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FastAutoGeneratorTest</span> {
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> {
FastAutoGenerator.create(<span class="hljs-string">"jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false"</span>, <span class="hljs-string">"root"</span>, <span class="hljs-string">"root123456"</span>)
.globalConfig(builder -> {
builder.author(<span class="hljs-string">"有勇气的牛排"</span>) <span class="hljs-comment">// 设置作者</span>
.enableSwagger() <span class="hljs-comment">// 开启 swagger 模式</span>
.fileOverride() <span class="hljs-comment">// 覆盖已生成文件</span>
.outputDir(<span class="hljs-string">"E://java//MyBatisPlus//tmp"</span>); <span class="hljs-comment">// 指定输出目录</span>
})
.packageConfig(builder -> {
builder.parent(<span class="hljs-string">"com.couragesteak"</span>) <span class="hljs-comment">// 设置父包名</span>
.moduleName(<span class="hljs-string">"mybatisplus"</span>) <span class="hljs-comment">// 设置父包模块名</span>
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, <span class="hljs-string">"E://java//MyBatisPlus//tmp"</span>)); <span class="hljs-comment">// 设置mapperXml生成路径</span>
})
.strategyConfig(builder -> {
builder.addInclude(<span class="hljs-string">"c_user"</span>) <span class="hljs-comment">// 设置需要生成的表名</span>
.addTablePrefix(<span class="hljs-string">"t_"</span>, <span class="hljs-string">"c_"</span>); <span class="hljs-comment">// 设置过滤表前缀</span>
})
.templateEngine(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FreemarkerTemplateEngine</span>()) <span class="hljs-comment">// 使用Freemarker引擎模板,默认的是Velocity引擎模板</span>
.execute();
}
}
</code></div></pre>
<h2><a id="12__1315"></a>12 多数据源</h2>
<p>适用于多种场景:纯粹多库、读写分离、一主多从、混合模式等。</p>
<p>创建两个库:mybatis_plus、mybatis_plu_1(新建),将mybatis_plus库的product表移动到mybatis_plu_1库,通过一个测试用例,分别获取用户数据商品数据,如果获取到说明,多库模拟成功。</p>
<p>引入依赖</p>
<pre><div class="hljs"><code class="lang-xml"><span class="hljs-comment"><!-- 多数据源 --></span>
<span class="hljs-tag"><<span class="hljs-name">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>com.baomidou<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>dynamic-datasource-spring-boot-starter<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">version</span>></span>3.5.0<span class="hljs-tag"></<span class="hljs-name">version</span>></span>
<span class="hljs-tag"></<span class="hljs-name">dependency</span>></span>
</code></div></pre>
<p>yml配置</p>
<pre><div class="hljs"><code class="lang-yaml"><span class="hljs-attr">spring:</span>
<span class="hljs-comment"># 配置数据源信息</span>
<span class="hljs-attr">datasource:</span>
<span class="hljs-attr">dynamic:</span>
<span class="hljs-comment"># 设置默认的数据源 或者 数据源组,默认值即为master</span>
<span class="hljs-attr">primary:</span> <span class="hljs-string">master</span>
<span class="hljs-comment"># 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源</span>
<span class="hljs-attr">strict:</span> <span class="hljs-literal">false</span>
<span class="hljs-attr">datasource:</span>
<span class="hljs-attr">master:</span>
<span class="hljs-attr">url:</span> <span class="hljs-string">jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false</span>
<span class="hljs-attr">driver-class-name:</span> <span class="hljs-string">com.mysql.cj.jdbc.Driver</span>
<span class="hljs-attr">username:</span> <span class="hljs-string">root</span>
<span class="hljs-attr">password:</span> <span class="hljs-string">root123456</span>
<span class="hljs-attr">slave_1:</span>
<span class="hljs-attr">url:</span> <span class="hljs-string">jdbc:mysql://localhost:3306/mybatis_plus_1?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false</span>
<span class="hljs-attr">driver-class-name:</span> <span class="hljs-string">com.mysql.cj.jdbc.Driver</span>
<span class="hljs-attr">username:</span> <span class="hljs-string">root</span>
<span class="hljs-attr">password:</span> <span class="hljs-string">root123456</span>
</code></div></pre>
<p>指定数据源,可以是实体,也可以是Service</p>
<p>UserServiceImpl实现类</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Service</span>
<span class="hljs-meta">@DS("master")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserServiceImpl</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">ServiceImpl</span><UserMapper, User> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">UserService</span> {
}
</code></div></pre>
<p>ProductServiceImpl 实现类</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Service</span>
<span class="hljs-meta">@DS("slave_1")</span> <span class="hljs-comment">//指定所操作的数据源</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">ProductServiceImpl</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">ServiceImpl</span><ProductMapper, Product> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">ProductService</span> {
}
</code></div></pre>
<h2><a id="13_MyBatisX_1382"></a>13 MyBatisX插件</h2>
<p>idea安装插件:MyBatisX</p>
<p>官方文档:https://baomidou.com/pages/ba5b24/#功能</p>
<p><img src="https://static.couragesteak.com/article/83fe471cc9d58f81f3d021a2bccf88bb.png" alt="image.png" /></p>
<h3><a id="131_mapperservice_1390"></a>13.1 生成实体、mapper、service、<strong>映射文件</strong></h3>
<p>需要连接数据源</p>
<p><img src="https://static.couragesteak.com/article/486db0a038ce1f6e30232feb1802131f.png" alt="image.png" /></p>
<p><img src="https://static.couragesteak.com/article/59ef991ef2c719f93b1af1c68c4c4eb7.png" alt="image.png" /></p>
<p><img src="https://static.couragesteak.com/article/9c733ddf2fc56c24388da59c7f30e059.png" alt="image.png" /></p>
<h3><a id="132__insert_1404"></a>13.2 生成 insert语句</h3>
<p>生成MyBatisSQL</p>
<p><img src="https://static.couragesteak.com/article/2c386c02af9304db9399db7b90647cf0.png" alt="image.png" /></p>
<p><img src="https://static.couragesteak.com/article/1a0c9ed0bcfca540b3a33ba18b765f20.png" alt="image20230320213123587.png" /></p>
<p><img src="https://static.couragesteak.com/article/b0dc96ba7166e16fbb12886dcc870b2e.png" alt="image.png" /></p>
<h3><a id="133_delete_1416"></a>13.3 生成delete语句</h3>
<p>插入</p>
<p><img src="https://static.couragesteak.com/article/71fbdaf420a0abb9fd3bf1375e3cda2c.png" alt="image20230320213223147.png" /></p>
<p>删除</p>
<pre><div class="hljs"><code class="lang-shell"><span class="hljs-meta"># </span><span class="language-bash">根据ID和用户名删除</span>
deleteByIdAndName
int deleteByIdAndName(@Param("id") Long id, @Param("name") String name);
<delete id="deleteByIdAndName">
delete
from c_product
where id = #{id,jdbcType=NUMERIC}
AND name = #{name,jdbcType=VARCHAR}
</delete>
</code></div></pre>
<p>这也太厉害这</p>
<ul>
<li>多个条件用And连接即可</li>
</ul>
<p>查询</p>
<pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">// 按照年龄降序</span>
selectAllOrderByAgeDesc
</code></div></pre>
<p>[1] 感谢尚硅谷</p>
留言