MybatisPlus工具(详细教程)

MybatisPlus

简介:是一个 MyBatis 的增强工具

官方网站:https://baomidou.com/

官方文档:https://baomidou.com/pages/24112f/

基本使用

导入包:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3</version>
</dependency>

数据源配置:

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    # 如果使用 MySQL8 驱动不同,增加时区的配置 serverTimezone=GMT%2B8
    url: jdbc:mysql://xx:3306/数据库?useSSL=false&useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 默认日志
  mapper-locations: classpath:/mapper/**/*.xml

基本使用:

启动类增加扫描mapper文件夹,省略@mapper注解

@MapperScan("指定Mapper接口所在的包")

mapper层编写

@Repository // 持久层
public interface BillMapper extends BaseMapper<Bill> {}

service层编写

需要继承IService

public interface BillService extends IService<Bill> {}

service实现类编写

@Service
public class BillServiceImpl extends ServiceImpl<BillMapper, Bill> implements BillService {}

常用注解

TableName

实体对应表名

@TableName("wms_ware_info")

TableId

主键注解

@TableId(value = "bid",type = IdType.AUTO)

type类型常见值:

  • AUTO 数据库ID自增
  • NONE 无状态
  • INPUT insert前自行set主键值
  • ASSIGN_ID 雪花算法生产id
  • ASSIGN_UUID UUID
  • ID_WORKER 分布式全局唯一ID,长整型类型,32位UUID字符串
  • ID_WORKER_STR 分布式全局唯一ID 字符串类型

注意:雪花算法:分布式ID生成算法,结果是一个long型的ID

TbaleField

设置实体类中的属性名和字段名注解

@TbaleField("user_name")
# 表中新增字段 create_time,update_time 创建时间/修改时间
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

# 如果为null,字段也更新为null
@TableField(updateStrategy = FieldStrategy.IGNORED)

# 表示不是数据库里的字段
@TableField(exist = false)
    
# MyMetaObjectHandler@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    // 插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
    }

    // 更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
    }
}

TableLogic

逻辑删除 (假删除)

// 逻辑删除  value 1:未删除的值  、delval 0 :删除后的值
@TableLogic(value = "1", delval = "0")
private Integer isDeleted; // 默认0 未删除 1已删除
# 配置文件
  logic-delete-field: flag  # 全局逻辑删除的实体字段名
  logic-delete-value: 1     # 逻辑已删除值(默认为 1)
  logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

通用枚举

设置枚举类、实体字段设置

@Getter
public enum SexEnum {
    MALE(1, "男"),
    FEMALE(2, "女");

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

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

# 实体字段设置
private SexEnum sex;

# 配置文件 - 增加配置
# 扫描通用枚举的包
type-enums-package: com.atguigu.mybatisplus.enums    

测试

@Test
public void test(){
    User user = new User();
    user.setName("admin");
    user.setSex(SexEnum.MALE);  // 保持数据库是key值
    int result = userMapper.insert(user);
}

基本API

Mapper层

// 1. 查询全部数据
List<Emp> emps = empMapper.selectList(null);

// 2. 新增
Emp emp1 = new Emp();
emp1.setAge(13);
int insert = empMapper.insert(emp1);

// 3. 删除
int i = empMapper.deleteById(9L); // 参数id
// 3.1 批量删除
int i1 = empMapper.deleteBatchIds(Arrays.asList(11L, 10L));
// 3.2 根据条件删除  注:key 是表字段
Map<String,Object> mapdel = new HashMap<>();
mapdel.put("name","修改的");
empMapper.deleteByMap(mapdel);

// 4. 修改
Emp emp2 = new Emp();
emp2.setId(12);
emp2.setName("修改的");
int i2 = empMapper.updateById(emp2);

// 5. 查询 
Emp empO = empMapper.selectById(12L);
List<Emp> all = empMapper.selectBatchIds(Arrays.asList(1L, 2L));
System.out.println(all);
// 5.1 根据查询条件查询,注:key 是表字段
Map<String,Object> map = new HashMap<>(); 
map.put("name","修改的");map.put("age","13");
List<Emp> bills = empMapper.selectByMap(map);

Service层

// 1.查出总记录数
long count = empService.count();
// long count2 = empService.count(new QueryWrapper<Emp>());
System.out.println(count);
// 2.根据主键id查询
Emp byId = empService.getById(3L);
// 3.查询全部
List<Emp> all = empService.list();
// List<Emp> all2 = empService.list(new QueryWrapper<Emp>());
System.out.println(all);

// 4.新增
empService.save(new Emp());
// 5.修改
empService.updateById(new Emp());
// empService.update(new QueryWrapper<Emp>());
// 6.新增或修改 , 有主键代表修改,否则新增
empService.saveOrUpdate(new Emp());
// 7.批量新增
List<Emp> alls = Arrays.asList(
    new Emp("王1", 1),
    new Emp("琳2", 33),
    new Emp("凯3", 32));
boolean b = empService.saveBatch(alls);
// 8.批量新增或修改 , 有主键代表修改,否则新增
empService.saveOrUpdateBatch(alls);

// 9.根据主键 删除
empService.removeById(20L);
empService.remove(new QueryWrapper<Emp>());
// 10.批量删除
empService.removeBatchByIds(Arrays.asList(11L, 10L));

条件构造器

Wrapper介绍:

Wrapper 条件构造抽象类

AbstractWrapper 用于查询条件封装,生成 sql 的 where 条件

  • QueryWrapper 查询条件封装
  • UpdateWrapper 修改条件
  • AbstractLambdaWrapper 使用Lambda 语法,它还有LambdaQueryWrapper 、LambdaUpdateWrapper

QueryWrapper:

查询条件

//查询用户名包含a,年龄在20到30之间,邮箱信息不为null的用户信息
QueryWrapper<User> q = new QueryWrapper<>();
q.like("username","a").between("age",20,30).isNotNull("email");
//排序条件 orderByDesc 降序 orderByAsc 升序
q.orderByDesc("age").orderByAsc("id");
List<User> users = userMapper.selectList(q);
users.forEach(System.out::println);

删除条件

 QueryWrapper<User> q = new QueryWrapper<>();
 q.isNull("email");
 int result = userMapper.delete(q);
 System.out.println(result > 0 ? "删除成功!" : "删除失败!");

条件的优先级

QueryWrapper<User> q = new QueryWrapper();
q.select("bill_name","bill_num","pay"); // select查询 只显示这几个字段,其他字段不显示
// ge 大于等于 gt 大于 le 小于等于  lt 小于
q.gt("bill_num",4)
 .and(i->{
    i.like("bill_name","a").or().isNull("pay");
 }).isNull("pay");
List<Map<String, Object>> maps = userMapper.selectMaps(q);

子查询

QueryWrapper<User> q = new QueryWrapper<>();
q.inSql("uid", "select uid from 表 where uid <= 100");
List<User> list = userMapper.selectList(q);

UpdateWrapper:

UpdateWrapper<User> u = new UpdateWrapper<>();
u.like("username","a")
 .set("email","修改的字段").set("bill_name","修改的字段2");
int result = userMapper.update(null, u);
System.out.println(result > 0 ? "修改成功!" : "修改失败!");

condition:

String  a = "a";
Integer b = null;
Integer c = 30;
QueryWrapper<User> q = new QueryWrapper<>();
// 参数 1 boolean值,满足条件会执行
q.like(StringUtils.isNotBlank(a), "user_name", a)  
    .ge(b != null, "age", b)
    .le(c != null, "age", c);
List<User> list = userMapper.selectList(q);

LambdaQueryWrapper:

String  a = "a";
Integer b = null;
Integer c = 30;
LambdaQueryWrapper<User> q = new LambdaQueryWrapper<>();
q.like(StringUtils.isNotBlank(a), User::getName, a)
    .ge(b != null, User::getAge, b)
    .le(c != null, User::getAge, c);
List<User> list = userMapper.selectList(q);

LambdaUpdateWrapper:

LambdaUpdateWrapper<User> u = new LambdaUpdateWrapper<>();
u.like(User::getName, "a").isNull(User::getEmail));
u.set(User::getName, "小黑").set(User::getEmail,"xxx");
int result = userMapper.update(null, u);

常用插件

分页

配置类

@Configuration
@MapperScan("com.yan.mybatis.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分页插件 - 指向数据库类型
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

测试

@Test
public void test1(){
    // 参数:当前页、显示条数、查询条件
    Page<Bill> page = billMapper.selectPage(new Page<>(1, 5), null);
    List<Bill> users = page.getRecords();
    users.forEach(System.out::println);
    System.out.println(page.getRecords());  // 获取记录数
    System.out.println(page.getSize());     // 获取显示条数
    System.out.println(page.getCurrent());  // 获取当前页的页码
    System.out.println(page.getPages());    // 获取总页码
    System.out.println(page.getTotal());    // 获取总记录数
    boolean b1 = page.hasNext();      // 是否有下一页
    boolean b2 = page.hasPrevious();  // 是否有上一页
}

自定义分页

# Mapper层定义
Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);

# XMl定义
<select id="selectPageVo" resultType="User">
    select * from t_user where age > #{age}
</select>    

# 测试
Page<User> page = userMapper.selectPageVo(new Page<User>(1,2), 20);
List<User> users = page.getRecords();    

乐观锁

乐观锁:保持乐观状态,无论干什么都不会上锁,如果有问题就再次更新值测试。(版本号version)

悲观锁:总是认为总会出现问题,无论干什么都会上锁后再去操作。

配置类

@Configuration
@MapperScan("com.yan.mybatis.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分页插件 - 指向数据库类型
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //添加乐观锁插件
    	interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

实体字段增加注解

@Version  // 标识乐观锁版本号字段
private String version;

测试

@Test
public void test1(){
    // 1.B1 获得的值
    Bill b1 = billMapper.selectById(16);
    System.out.println("B1 :" + b1.getMoney());
    // 2.B2 获得的值
    Bill b2 = billMapper.selectById(16);
    System.out.println("B2 :" + b1.getMoney());

    // 3.B1 获得的值 + 50
    b1.setMoney(b1.getMoney() + 50);
    billMapper.updateById(b1);

    // 4.B2 获得的值 - 30
    b2.setMoney(b2.getMoney()-30);
    int result = billMapper.updateById(b2);
    if (result == 0) {
        // 操作失败,重试
        Bill b = billMapper.selectById(16);
        b.setMoney(b.getMoney() - 30);
        billMapper.updateById(b);
    }

    // 5.查看 16这条数据 值 - 乐观锁
    Bill bill = billMapper.selectById(16);
    System.out.println("Bill :" + bill.getMoney());

}

注意:

整数类型下 newVersion = oldVersion + 1
newVersion 会回写到 entity 中
仅支持 updateById(id) 与 update(entity, wrapper) 方法
在 update(entity, wrapper) 方法下, wrapper 不能复用

通用枚举

枚举类

import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;

/**
 * 枚举
 */
@Getter
public enum SexEnum {

    ONE(0, "未付款"),
    TWO(1, "已付款");

    @EnumValue // 将注解所标识的属性的值存储到数据库中
    private int index;
    private String name;

    SexEnum(Integer index, String name) {
        this.index = index;
        this.name = name;
    }

}

配置文件需要配置

type-enums-package: cn.good.yan.pojo.conf

实体需要引用

private SexEnum pay;

代码生成器

导入依赖包

<!-- 代码生成器 -->
<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>

测试

// 代码生成器
public static void main(String[] args) {
    FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/数据库名?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8", "用户名", "密码")
        .globalConfig(builder -> {
            builder.author("yan") // 设置作者
                // .enableSwagger() // 开启 swagger 模式
                .fileOverride() // 覆盖已生成文件
                .outputDir("G://xx"); // 指定输出目录
        })
        .packageConfig(builder -> {
            builder.parent("com.yan") // 设置父包名
                .moduleName("mybatis") // 设置父包模块名
                .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "G://xx/mapper")); // 设置mapperXml生成路径
        })
        .strategyConfig(builder -> {
            builder.addInclude("pms_spu_comment") // 设置需要生成的表名
                .addTablePrefix("t_", "pms_");    // 设置过滤表前缀
        })
        // 使用Freemarker引擎模板,默认的是Velocity引擎模板
        .templateEngine(new FreemarkerTemplateEngine()) 
        .execute();
}

多数据库

适用场景:读写分离、一主一从、多库

导入依赖包

<!-- 多数据源 -->
<dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
   <version>3.5.0</version>
</dependency>

更改配置

spring:
  datasource:
    # 配置多数据源
    dynamic:
      # 设置默认的数据源或者数据源组,默认值即为master
      primary: master
      # 严格匹配数据源,默认false 如:true未匹配到指定数据源时抛异常,false使用默认数据源,也就是主数据源
      strict: false
      datasource:
        master:
          url: jdbc:mysql://127.0.0.1:3306/数据库1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: 用户名
          password: 密码
        slave:
          url: jdbc:mysql://127.0.0.1:3306/数据库2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: 用户名
          password: 密码

指定操作数据源

// 指定操作的数据源,master  - 也可以放在具体的方法上,和类上,就近原则取对应的数据源
@DS("master")
public interface UserService extends IService<User> {}
// ---
@DS("slave")
public interface BillService extends IService<Bill> {}

测试

@Autowired
private BillService billService;
@Autowired
private UserService userService;

@Test
public void test(){
    Bill b1 = billService.getById(16);
    System.out.println(b1);

    User u1 = userService.getById(2);
    System.out.println(u1);
}

MyBatisX插件

MyBatisX一款基于 IDEA 的快速开发插件,简化我们开发。在IDEA的插件里进行下载MyBatisX。

IDEA中与数据库建立链接:

找到我们要生成的表

image-20220911234032561

然后点击,填写第一页

image-20220911234904774

填写第二页

操作完成 - 快速生成对应的文件

然后我们开发过程中快速生成CRUD操作:

image-20220911235946963

选择这个,可以快速生产对应的代码和XML映射文件

感谢观看,代码案例:优秀的颜/MybatisPlus

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值