MyBatisPlus:MyBatisPlus入门

MyBatisPlus

Mybatis-Plus是一个MyBatis的增强工具,在mybatis的基础上只做增强不做改变

简化开发,提高效率

MP的特性

无侵入

只做增强不做改变

损耗小

启动时自动注入基本CRUD,性能几乎无循环

强大的CRUD操作

内置通用Mapper和Service实现大部分单表操作

支持Lambda形式调用

通过Lambda表达式编写各类的查询条件

支持主键自动生成

支持4种主键策略(自增,雪花算法,UUID等)

支持ActiveRecord模式

实体类继承Model即可进行CRUD操作

支持自定义全局通用操作

全局通用方法注入

内置代码生成器

可快速生成各层代码

内置分页插件

基于MyBatis进行物理分页

分页插件支持多种数据库
内置性能分析插件
内置全局拦截插件

MyBatisPlus配置

依赖注入

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

配置Datasource

//控制台打印sql配置
#mybatis-plus配置控制台打印完整带参数SQL语句
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

定义实体类

package com.cfjg.pojo;

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

/**
 * 实体类基于注解与表进行映射
 */
@Data
@Builder
// 指定表名
@TableName("tb_user") 
@NoArgsConstructor
@AllArgsConstructor
public class User {
	//主键字段注解
	//设置主键自动生成方法
	//AUTO(0),increment自增
    //NONE(1),跟随全局
    //INPUT(2),自定义主键,自己输入
    //ASSIGN_ID(3),雪花算法
    //雪花算法生成的id为19为数字,由时间戳/数据中心/机器标识/序列号四个部分组成
    //ASSIGN_UUID(4);UUID
	@TableId(value = "id",type = IdType.AUTO)
    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;
    
    //忽略该属性和数据库表中的映射关系
    @TableField(exist = false)
    private String ignore
}

MyBatisPlus实现数据库操作

在Mapper层继承BaseMapper

//泛型内写表对应的实体类类型
UserMapper extends BaseMapper<User>    
普通单表操作都在接口中进行定义
直接调用接口方法即可
注:MP的更新操作不会将属性的空值覆盖原本的值
 @Test
    public void testUserInsert(){
        User user = User
                .builder()
                .age(19)
                .build();
        userMapper.insert(user);
    }

分页查询

需要先配置分页拦截器
@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        // paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量,-1不受限制
        paginationInterceptor.setMaxLimit(-1L);
        interceptor.addInnerInterceptor(paginationInterceptor);
        return interceptor;
    } 
}
进行分页查询
 	@Test
    public void testSelectPage() {
        //创建分页对象,查询完成数据会回填到page对象中
        Page<User> page = new Page<>(1,2);
        //构建条件对象
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("age","19");

        userMapper.selectPage(page, wrapper);
        System.out.println(page.getRecords());
        System.out.println(page.getTotal());
        System.out.println(page.getPages());
    }

条件查询

使用wrapper接口实现条件查询和更新

//查询接口
QueryWrapper
//更新接口
UpdateWrapper

QueryWrapper常用API

//equal
eq( ) :  等于 =
//not equal
ne( ) :  不等于 <> 或者 !=
//greater than
gt( ) :  大于 >
//greater equal
ge( ) :  大于等于  >=
//less than
lt( ) :  小于 <
//less equal
le( ) :  小于等于 <=
or():或
between ( ) :  BETWEEN1 AND2 
notBetween ( ) :  NOT BETWEEN1 AND2 
in( ) :  in
notIn( ) :not in
like(): like模糊查询%xxx%
likeLeft():左侧模糊查询%xxx
likeRight():右侧模糊查询xxx%
orderByAsc()
orderByDesc()
条件查询操作
	@Test
    public void testCondition(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("age",19).or().lt("age",30);
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
限定字段查询

通过wrapper限定select查询的字段

 wrapper.eq("age",19).or().lt("age",30).select("age");

LambdaQueryWrapper查询

避免使用普通wrapper时出现的硬编码列名问题,通过传入对应属性值的get方法解析出这个属性对应的字段

	@Test
    public void testLambdaSelect(){
        LambdaQueryWrapper<User> eq = Wrappers.<User>lambdaQuery()
                .eq(User::getAge, 19);
        userMapper.selectList(eq);

        Wrappers.<User>lambdaUpdate()
                .eq(User::getAge,19);
    }
LambdaQueryWrapper删除
	@Test
    public void testDelete(){
        LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery()
                .gt(User::getAge, 19);
        userMapper.delete(wrapper);
    }
LambdaQueryWrapper更新
	@Test
    public void testUpdate(){
        LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery()
                .eq(User::getUserName,null);
        User user = new User();
        user.setName("a");
        user.setAge(11);
        user.setUserName("b");
        userMapper.update(user,wrapper);
    }

定义查询接口实现分页查询

对自定义SQL语句进行分页查询

	@Test
    public void sqlTest(){
        Page<User> page = new Page<>(1,2);
        userMapper.findGtIdByPage(page,1);
        page.getRecords().forEach(System.out::println);
    }

mybatisplus对应的xml文件在resource下的/mapper/**/*.xml读取

sql:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.UserMapper">

    <select id="findGtIdByPage" resultType="com.itheima.pojo.User">
        select * from tb_user where id > #{id}
    </select>
</mapper>
通过${ew.}实现条件构造器复用
Wrapper ew

//传入构造器替换select后的内容
${ew.sqlSelect}

//传入构造器替换sql中的条件,放在where后面
{ew.customSqlSegment}

MP实现Service封装

继承公共接口
//service接口继承Iservice接口
public interface UserService extends IService<User>

//service实现类继承ServiceImpl接口
//泛型内写Mapper对象和实体类对象
public class UserServiceImpl extends ServiceImpl<UserMapper, User>

MP封装Service实现CRUD操作

大体和持久层一致

先构造条件构造器

再传入条件构造器实现条件查询

    @Test
    public void UserTest(){
        LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery()
                .eq(User::getUserName,"test");
        System.out.println(userService.list(wrapper));
    }

MP代码生成器

自动生成控制层业务层mapper层和xml代码

只需指定数据库和生成的表名即可

导入依赖
<!--mp 代码生成器-->
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-generator</artifactId>
  <version>3.5.5</version>
</dependency>
<dependency>
  <groupId>org.freemarker</groupId>
  <artifactId>freemarker</artifactId>
  <version>2.3.31</version>
</dependency>
代码生成器
package com.itheima;

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.sql.Types;
import java.util.Collections;

public class CodeGenerator {

    public static void main(String[] args) {
        String url = "jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
        String username = "root";
        String password = "root";
        FastAutoGenerator.create(url, username, password).globalConfig(builder -> {
                    builder.author("itheima") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .outputDir("F:\\code\\mp"); // 指定输出目录
                }).dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
                    int typeCode = metaInfo.getJdbcType().TYPE_CODE;
                    if (typeCode == Types.SMALLINT) {
                        // 自定义类型转换
                        return DbColumnType.INTEGER;
                    }
                    return typeRegistry.getColumnType(metaInfo);
                })).packageConfig(builder -> {
                    builder.parent("com.itheima") // 设置父包名
                            .moduleName("user") // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, "F:\\code\\mp")); // 设置mapperXml生成路径
                }).strategyConfig(builder -> { //策略配置
                    builder.addInclude("tb_user")  // 设置需要生成的表名
                            .addTablePrefix("tb_") // 设置过滤表前缀

                            .entityBuilder() //设置实体构建器,设置属性
                            .enableFileOverride() //文件覆盖
                            .enableLombok() //开启lombok

                            .controllerBuilder().enableRestStyle() //启用RestController
                            .enableFileOverride() //文件覆盖

                            .mapperBuilder().enableBaseResultMap() //开启生成 resultMap 结果映射
                            .enableFileOverride() //文件覆盖
                    ;
                }).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();
    }
}

MybatisPlus逻辑删除

即在数据库中添加一个is_delete字段用来表示数据是否被删除

而非真的将数据删除,只是对数据进行标注

用这种方法删除的数据是可逆的,可以恢复

mybatisplus配置逻辑删除
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
实体类字段加@TableLogic注释
@TableLogic
private Integer is_deleted;

开启逻辑删除功能后,mp在删除查询和更新时会自动加上逻辑删除字段为未删除的条件

MybatisPlus乐观锁

相对于悲观锁而言,乐观锁假设数据在一般情况下不会发生冲突

只有在数据进行提交和更新时才会正式对数据的冲突与否进行检测

如果冲突,则返回错误的信息让用户决定后续操作

相比于悲观锁,并发下的程序吞吐量更大

乐观锁的实现方式

版本号控制

通过数据量增加一个version版本字段,判断每次读取的version版本和数据库记录的是否一致,如果不一致则过期

//通过对实体类字段添加@version注解来标记锁
@version
private Integer version
注册配置类

需要先注册乐观锁插件(乐观锁拦截器)

//扫描我们的repository文件夹
@MapperScan("com.trainingl.repository")
@EnableTransactionManagement
@Configuration  //配置类
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //注册乐观锁插件
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
    
}

MybatisPlus自动填充

对于创建时间create_time,更新时间update_time这些每次对数据修改时都要设置的字段,如果在代码中进行手动设置会显得冗余且容易出错

mp提供了自动填充的功能

实现过程

通过给实体类添加@TableField注解来进行指定填充的时间

FieldFill字段枚举类四种自动填充处理策略,分别是Default (默认不处理)、Insert (插入时填充)、Update (更新时填充)、Insert_Update (插入和更新时填充)

	@TableField(fill = FieldFill.INSERT)
    private LocalDateTime creatTime;
 
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

再通过实现MetaObjectHandler接口对填充策略进行设计

/**
 * mybatis-plus自动填充策略设置
 */
@Slf4j
@Component
public class DatetimeMetaObjectHandler implements MetaObjectHandler {
    //进行插入时填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("mybatis-plus 开始在你插入的时候 字段填充字段......");
        this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
        this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
    }
 
    //进行修改操作时填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("mybatis-plus 开始在你修改的时候 字段填充字段......");
        this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
    }
}

MybatisPlus通用枚举

实现数据库存入时指定值保存,读取时指定值展示

通过继承IEnum,@EnumValue实现

读取数据时可以通过使用@JsonValue执行显示的值

@AllArgsConstructor
public enum SexEnum implements IEnum<Integer> {
 
    boy(0, "男孩"),
    girl(1, "女孩");
 
 
    private final Integer code;
    // 序列化枚举值为 接口出参;接口入参(RequestBody),反序列化为枚举值
    @JsonValue
    private final String name;
 
 
    @Override
    public Integer getValue() {
        return code;
    }
}

@AllArgsConstructor
public enum SexEnum {
 
    boy(0, "男孩"),
    girl(1, "女孩");
 
 
    @EnumValue
    private final Integer code;
    @JsonValue
    private final String name;
 

}

MybatisPlus拦截器插件

防全表更新和删除插件

全表更新时会抛出异常

@Configuration
public class MybatisPlusConfig {
    //拦截器
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //注册分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //注册防全表更新与删除插件
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        return interceptor;
    }
}

MybatisPlus流式查询

流式查询:查询成功后不是返回一个集合而是返回一个迭代器,每次从迭代器取出一条结果进行查询

可以有效的降低内存使用

执行流式查询时,框架不负责对数据库连接进行关闭,需要在取完数据之后进行关闭

Mybatis的流式查询

提供了一个Cursor接口用于流式查询

继承了 java.io.Closeable 和 java.lang.Iterable 接口

所以流式查询的过程是可关闭和可遍历的

提供了三个方法

//用于在取数据之前判断 Cursor 对象是否是打开状态。只有当打开时 Cursor 才能取数据
isOpen()
//用于判断查询结果是否全部取完
isConsumed()
//返回已经获取了多少条数据
getCurrentIndex()
MyBatisPlus实现流式查询

需要自定义接口实现

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值