空白无上
Notes Mybatis Plus

Mybatis Plus

导入依赖 pom.xml 文件 xml <dependency <groupId org.springframework.boot</groupId <artifactId spring boot starter web</artifactId </dependency <dependency <groupId com

导入依赖

pom.xml 文件

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
xml

修改配置文件

spring:
  # 数据源信息
  datasource:
    # 配置数据源类型
    type: com.zaxxer.hikari.HikariDataSource
    # 配置连接数据库的各个信息
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false
    username: root
    password: hsy031122
yaml

实体类

创建User类

package xyz.kbws.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author hsy
 * @date 2023/7/13
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;

    private String name;

    private Integer age;

    private String email;
}
java

创建UserMapper接口

UserMapper

package xyz.kbws.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import xyz.kbws.pojo.User;

/**
 * @author hsy
 * @date 2023/7/13
 */
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
java

操作

查询

创建测试类 MybatisPlusTest

package xyz.kbws.mybatisplus;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import xyz.kbws.mapper.UserMapper;
import xyz.kbws.pojo.User;

import java.util.List;

/**
 * @author hsy
 * @date 2023/7/13
 */
@SpringBootTest
public class MybatisPlusTest {
    @Autowired
    UserMapper userMapper;

    @Test
    public void testSelectList(){
        //通过条件构造器查询一个List集合,若没有条件,可以设置null作为参数
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}
java

插入

@Test
public void testInsert(){
    User user = new User();
    user.setId(6L);
    user.setName("hsy");
    user.setAge(21);
    user.setEmail("hsy040506@163.com");
    userMapper.insert(user);
}
java

删除

@Test
public void testDelete(){
    userMapper.deleteById(6L);
}
java

开启日志

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
yaml

创建Service接口

package xyz.kbws.service;

import com.baomidou.mybatisplus.extension.service.IService;
import xyz.kbws.pojo.User;

/**
 * @author hsy
 * @date 2023/7/13
 */
public interface UserService extends IService<User> {
}
java

实现Service接口

package xyz.kbws.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import xyz.kbws.mapper.UserMapper;
import xyz.kbws.pojo.User;
import xyz.kbws.service.UserService;

/**
 * @author hsy
 * @date 2023/7/13
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
java

查询数量

@Test
public void testGetCount(){
    int count = userService.count();
    System.out.println(count);
}
java

批量插入

@Test
public void testInsertBatch(){
    List<User> list = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        User user = new User();
        user.setName("ybc"+i);
        user.setAge(20+i);
        list.add(user);
    }
    boolean b = userService.saveBatch(list);
    System.out.println(b);
}
java

常用注解

@Table-name

当实体类的名字为user,数据库中的表为t_user时

package xyz.kbws.pojo;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author hsy
 * @date 2023/7/13
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")//设置实体类所对应的表名
public class User {
    private Long id;

    private String name;

    private Integer age;

    private String email;
}
java

也可以使用全局配置

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # mybatis-plus的全局配置
  global-config:
    db-config:
      # 设置实体类所对应表的前缀
      table-prefix: t_
yaml

@TableId

Mybatis Plus 默认把 id 作为主键,如果实体类中没有 id,则需要指定一个主键,否则会报错

package xyz.kbws.pojo;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author hsy
 * @date 2023/7/13
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
    @TableId    //讲属性所对应的字段指定为主键
    private Long uid;

    private String name;

    private Integer age;

    private String email;
}
java

value属性

package xyz.kbws.pojo;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author hsy
 * @date 2023/7/13
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {

    //value属性用于指定主键的字段
    @TableId(value = "uid")
    private Long id;

    private String name;

    private Integer age;

    private String email;
}
java

type属性,用于指定主键的创建方式(默认为雪花算法)

package xyz.kbws.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author hsy
 * @date 2023/7/13
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {

    //type属性用于设置主键创建方式
    //AUTO为自增
    @TableId(type = IdType.AUTO)
    private Long id;

    private String name;

    private Integer age;

    private String email;
}
java

注意:type 设置为自增的时候,数据库的主键必须也设置为自增

全局设置主键生成策略

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # mybatis-plus的全局配置
  global-config:
    db-config:
      # 设置实体类所对应表的前缀
      table-prefix: t_
      # 设置统一的主键生成策略
      id-type: auto
yaml

@TableField

package xyz.kbws.pojo;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author hsy
 * @date 2023/7/13
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private Long id;

    //指定属性所对应的字段名
    @TableField("user_name")
    private String name;

    private Integer age;

    private String email;
}
java

@TableLogic

用于逻辑删除

package xyz.kbws.pojo;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author hsy
 * @date 2023/7/13
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {

    //value属性用于指定主键的字段
    @TableId(value = "uid")
    private Long id;

    private String name;

    private Integer age;

    private String email;

    @TableLogic
    private Integer isDelete;
}
java

条件构造器

Feishu image

QueryWapper

组装查询条件

@Test
public void test1(){
    QueryWrapper<User> query = new QueryWrapper<>();
    //查询用户名包含a,年龄在20到30之间,邮箱信息不为null的用户信息
    query.like("name","a").between("age",20,30).isNotNull("email");
    List<User> list = userMapper.selectList(query);
    System.out.println(list);

}
java

组装排序条件

@Test
public void test2(){
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //查询用户信息,按照年龄的降序排序,若年龄相同,则按照uid升序排序
    queryWrapper.orderByDesc("age").orderByAsc("uid");
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}
java

组装删除条件

@Test
public void test3(){
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //删除邮箱地址为null的用户
    queryWrapper.isNull("email");
    int delete = userMapper.delete(queryWrapper);
    System.out.println(delete);
}
java

此语句本质是一条更新语句,将数据的 is_delete 从 0 改成 1

实现修改功能

@Test
public void test4(){
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
    queryWrapper.gt("age",20)
            .like("name","a")
            .or()
            .isNull("email");
    User user = new User();
    user.setName("hsy");
    user.setEmail("hsy@163.com");
    int update = userMapper.update(user, queryWrapper);
    System.out.println(update);
}
java

条件的优先级

@Test
public void test5(){
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //将用户名中含有a并且(年龄大于20或邮箱为null)的用户信息修改
    //lambda中的条件优先执行
    queryWrapper.like("name", "a")
            .and(i->i.gt("age",20).isNull("email"));
    User user = new User();
    user.setName("hsy");
    user.setEmail("hsy@163.com");
    int update = userMapper.update(user, queryWrapper);
    System.out.println(update);
}
java

组装select语句

@Test
public void test6(){
    //查询用户的用户名、年龄、邮箱信息
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.select("name","age","email");
    List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
    maps.forEach(System.out::println);
}
java

实现子查询

@Test
public void test7(){
    //查询uid小于100的用户信息
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.inSql("uid","select uid from t_user where uid <= 100");
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}
java

UpdateWapper

修改功能

@Test
public void test8(){
    //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.like("name","a")
            .and(i->i.gt("age",20).or().isNull("email"));
    updateWrapper.set("name","小黑").set("email","abc@test.com");
    int update = userMapper.update(null, updateWrapper);
    System.out.println(update);
}
java

condition

@Test
public void test9(){
    String username="";
    Integer ageBegin=null;
    Integer ageEnd=30;
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like(StringUtils.isNotBlank(username),"name",username)
            .ge(ageBegin != null,"age",ageBegin)
            .le(ageEnd!=null,"age",ageEnd);
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}
java

LambdaQueryWapper

@Test
public void test10(){
    String username="";
    Integer ageBegin=null;
    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);
}
java

LambdaUpdateWapper

@Test
public void test11(){
    //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
    LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper.like(User::getName,"a")
            .and(i->i.gt(User::getAge,20).or().isNull(User::getEmail));
    updateWrapper.set(User::getName,"小黑").set(User::getEmail,"abc@test.com");
    int update = userMapper.update(null, updateWrapper);
    System.out.println(update);
}
java

插件

分页插件

添加配置类

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
java

测试

@Autowired
UserMapper userMapper;

@Test
public void test1(){
    Page<User> page = new Page<>(1,3);
    Page<User> userPage = userMapper.selectPage(page, null);
    System.out.println(userPage.getRecords());
}
java

XML自定义分页

UserMapper中定义接口方法

/**
 * 通过年龄查询用户信息并分页
 * @param page  Mybatis-Plus提供的分页对象,必须位于第一个参数的位置
 * @param age   用户的年龄
 * @return
 */
Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);
java

UserMapper.xml中编写SQL

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0/EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xyz.kbws.mapper.UserMapper">
    <select id="selectPageVo" resultType="User">
        select uid,name,age,email from t_user where age > #{age}
    </select>
</mapper>
xml

测试

@Test
public void test2(){
    Page<User> page = new Page<>(1,2);
    Page<User> page1 = userMapper.selectPageVo(page, 20);
    System.out.println(page1.getRecords());
}
java

乐观锁

场景

Feishu image

乐观锁和悲观锁

Feishu image

模拟修改冲突

数据库添加商品表

create table t_product(
    id bigint(20) not null comment '主键ID',
    name varchar(30) null default null comment '商品名称',
    price int(11) default 0 comment '商品价格',
    version int(11) default 0 comment '乐观锁版本号',
    primary key (id)
)comment '商品表';
sql

增加数据

insert into t_product (id, name, price) values (1,'外星人笔记本',100);
sql

增加实体

package xyz.kbws.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author hsy
 * @date 2023/7/15
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
    private Long id;
    private String name;
    private Integer price;
    private Integer version;
}
java

添加Mapper

@Mapper
public interface ProductMapper extends BaseMapper<Product> {
}
java

测试

@Test
public void test3(){
    //小李查询商品价格
    Product productLi = productMapper.selectById(1);
    //小王查询商品价格
    Product productWang = productMapper.selectById(1);
    //小李将商品价格+50
    productLi.setPrice(productLi.getPrice()+50);
    productMapper.updateById(productLi);
    //小王将商品价格-30
    productWang.setPrice(productWang.getPrice()-30);
    productMapper.updateById(productWang);
    //老板查询商品价格
    Product productLaoBan = productMapper.selectById(1);
    System.out.println(productLaoBan);
}
java

乐观锁实现流程

数据库中添加version字段

取出记录时获取当前version

select id,name,price,version from product where id=1;
sql

更新时version+1,如果where语句中的version版本不对,则更新失败

update product set price=price+50, version=version+1 where id=1 and version=1
sql

Mybatis Plus实现乐观锁

修改实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
    private Long id;
    private String name;
    private Integer price;
    @Version    //标识乐观锁版本号字段
    private Integer version;
}
java

添加乐观锁插件配置

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}
java

测试修改流程

Feishu image

通用枚举

表中有些字段值是固定的,例如性别(男或女),此时我们可以用MyBaits-Plus的通用枚举实现

数据库添加字段sex

Feishu image

创建通用型枚举

@Getter
public enum SexEnum {
    MAN(1,"男"),
    WOMAN(2,"女");

    @EnumValue  //将注解所标识的值存储到数据库中
    private Integer sex;
    private String sexName;

    SexEnum(Integer sex, String sexName) {
        this.sex = sex;
        this.sexName = sexName;
    }
}
java

配置扫描通用枚举

mybatis-plus:
  # 扫描通用枚举的包
  type-enums-package: xyz.kbws.enums
yaml

测试

@Test
public void test4(){
    User user = new User();
    user.setName("admin");
    user.setAge(33);
    user.setSex(SexEnum.MAN);
    int insert = userMapper.insert(user);
    System.out.println(insert);
}
java