MyBatis-Plus学习笔记

MyBatis-Plus官网

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

使用SpringBoot初始化

导入依赖

        <!-- Mysql驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
				<!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>
      	<!-- MyBatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>

:: 使用mybatis-plus 可以节省大量代码

连接数据库

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      # 主库数据源
      master:
        url: jdbc:mysql://localhost:3306/xxx?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: xxx
        password: xxx

mybatis-plus:
  # 搜索指定包别名
  typeAliasesPackage: com.ruoyi.**.domain
  # 配置mapper的扫描,找到所有的mapper.xml映射文件
  mapperLocations: classpath*:mapper/**/*Mapper.xml
  # 加载全局的配置文件
  #  configLocation: classpath:mybatis/mybatis-config.xml
  configuration:
    map-underscore-to-camel-case: false
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      logic-delete-field: isDelete # 全局逻辑删除的实体字段名
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

创建数据表

CREATE TABLE `user` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
  `userAccount` varchar(256) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '账号',
  `userPassword` varchar(512) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密码',
  `unionId` varchar(256) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '微信开放平台id',
  `mpOpenId` varchar(256) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '公众号openId',
  `userName` varchar(256) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户昵称',
  `userAvatar` varchar(1024) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户头像',
  `userProfile` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户简介',
  `userRole` varchar(256) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'user' COMMENT '用户角色:user/admin/ban',
  `createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `isDelete` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除',
  PRIMARY KEY (`id`),
  KEY `idx_unionId` (`unionId`)
) ENGINE=InnoDB AUTO_INCREMENT=1669963950083579906 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户'

创建pojo

package com.kkkkkba.search.model.entity;

import com.baomidou.mybatisplus.annotation.IdType;
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 java.io.Serializable;
import java.util.Date;

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

/**
 * 用户
 *

 */
@TableName(value = "user")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    /**
     * id
     */
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;

    /**
     * 用户账号
     */
    private String userAccount;

    /**
     * 用户密码
     */
    private String userPassword;

    /**
     * 开放平台id
     */
    private String unionId;

    /**
     * 公众号openId
     */
    private String mpOpenId;

    /**
     * 用户昵称
     */
    private String userName;

    /**
     * 用户头像
     */
    private String userAvatar;

    /**
     * 用户简介
     */
    private String userProfile;

    /**
     * 用户角色:user/admin/ban
     */
    private String userRole;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;

    /**
     * 是否删除
     */
    @TableLogic
    private Integer isDelete;

    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

创建Mapper


public interface UserMapper extends BaseMapper<User> {

}

使用Mybatis-Plus

在主启动类上配置Mapper接口

@MapperScan("com.kkkkkba.search.mapper")
CRUD
查询
    @Test
    void MyTest (){
        List<User> posts = userMapper.selectList(null);
        posts.forEach(System.out::println);
    }

image.png

插入
    @Test
    void Insert (){
        User user = new User();
        user.setUserName("kba");
        int insert = userMapper.insert(user);
        System.out.println(insert);
    }
主键生成策略

默认 ASSIGN_ID

雪花算法
雪花算法(snowflake)最早是twitter内部使用分布式环境下的唯一ID生成算法。
雪花算法使用64位long类型的数据存储id

自增 AUTO

实体类配置@TableId(type = IdType.AUTO)

其他

public enum IdType {
    AUTO(0), // 自增id
    NONE(1), // 未设置主键
    INPUT(2), // 手动输入
    ASSIGN_ID(3), //默认全局唯一id
    ASSIGN_UUID(4); // 全局唯一id uuid
}
更新
@Test
void update(){
    User user = new User();
    user.setId(1669963950083579905);
    user.setUserAccount("kbaaaaa");
    userMapper.updateById(user);
}
自动填充

创建时间,修改时间,应该自动化完成
:::info
方式一 数据库级别
:::

  1. 表中新增字段 create_time update_time
  2. 修改数据库字段

image.png

:::info
方式二 代码级别
:::

  1. 删除数据库的默认值
  2. 实体类字段属性添加字段
/**
 * 创建时间
 */
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date createTime;

/**
 * 更新时间
 */
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
  1. 编写处理器实现注释
@Slf4j 
@Component 
public class MyMetaObjectHandler implements MetaObjectHandler { 

    @Override 
    public void insertFill(MetaObject metaObject) { 
        log.info("start insert fill ...."); 
        this.strictInsertFill(createTime, new Date(), metaObject); 
        this.strictUpdateFill(updateTime, new Date, metaObject); 
    }

    @Override 
    public void updateFill(MetaObject metaObject) { 
        log.info("start update fill ...."); 
        this.strictUpdateFill(updateTime, new Date, metaObject); 
    } 
}
乐观锁

乐观锁,任何时候都不会上锁,出现问题在更新值测试
悲观锁: 任何时候都会上锁,再去操作

当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:

  • 取出记录时,获取当前 version
  • 更新时,带上这个 version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果 version 不对,就更新失败

测试

  1. 给数据库增加version字段 默认值为1
  2. 实体类增加对应的字段并增加@Version注解
  3. 注册组件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    return interceptor;
}
  1. 测试
// 测试乐观锁成功案例
@Test
void OptimisticLocker (){
    User user1 = new User();
    user1.setId(1669963950083579905L);
    user1.setUserName("乐观锁");
    userMapper.updateById(user1);
}

// 测试乐观锁失败
@Test
void OptimisticLockerError (){
    User user1 = new User();
    user1.setId(1669963950083579905L);
    user1.setUserName("乐观锁,线程1");

    User user2 = new User();
    user2.setId(1669963950083579905L);
    user2.setUserName("乐观锁,线程2");

    // 模拟插队任务
    userMapper.updateById(user2);

    userMapper.updateById(user1);   // 如果没有乐观锁就会覆盖插队线程的值
}
查询-Map
@Test
void Select1(){
    User user = userMapper.selectById(1669963950083579905L);
    System.out.println(user);
}
@Test
void Select2(){
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1669963950083579905L, 1664885844209651713L));
    users.forEach(System.out::println);
}

// Map 查询
@Test
void Select3(){
    HashMap<String, Object> map = new HashMap<>();
    // 自定义查询内容
    map.put("name","kkkkkba");
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);

}
分页插件
  1. 配置分页插件
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
        //interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
        return interceptor;
    }
}
  1. 测试分页查询
@Test
void Select4(){
    // 参数一 当前页
    // 参数二 页面大小
    Page<User> page = new Page<>(1,2);
    Page<User> pages = userMapper.selectPage(page, null);
    pages.getRecords().forEach(System.out::println);
    System.out.println(pages.getTotal());
}
删除
@Test
void Del(){
    //  id删除
    userMapper.deleteById(1669963950083579905L);
    //  批批量删除
    userMapper.selectBatchIds(Arrays.asList(1669963950083579905L, 1664885844209651713L))
    //  Map删除
    。。。。。。。
}
逻辑删除

物理删除: 从数据库中直接删除
逻辑删除: 在数据库中没有删除,定义一个变量让他失效

应用场景:管理员可以查看被删除的记录

  1. 在数据库中定义deleted字段
  2. 实体类中添加对应字段,添加@TableLogic注释
  3. 配置yml
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: isDelete # 全局逻辑删除的实体字段名
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
条件查询器

Wrapper 复杂SQL查询时使用
image.png

@Test
void Select1(){
    // 查询 unionId 不为空的user
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.isNotNull("unionId")
    .eq("userRole","user");

    userMapper.selectList(wrapper).forEach(System.out::println );
}

@Test
void Select2(){
    // 查询 userName == 赵今麦
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("userName","赵今麦");
    userMapper.selectList(wrapper).forEach(System.out::println );
}

@Test
void Select3(){
    // 查询 范围
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.YEAR, 2023);
    calendar.set(Calendar.MONTH, 5); // 月份从0开始,所以1月是0
    calendar.set(Calendar.DAY_OF_MONTH, 4);
    Date customDate = calendar.getTime();

    wrapper.between("createTime",customDate,new Date());
    userMapper.selectList(wrapper).forEach(System.out::println );
}

@Test
void Select4(){
    // 查询 用户名不包含kba 且 以l开头i结尾
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.notLike("userAccount","kba")
    .likeLeft("userAccount","l")
    .likeRight("userAccount","i");
    userMapper.selectList(wrapper).forEach(System.out::println );
}

@Test
void Select5(){
    // 查询 用户名不包含kba 且 以l开头i结尾
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.inSql("id","select id from user where userAccount like   '%kba%' ");
    userMapper.selectList(wrapper).forEach(System.out::println );
}
@Test
void Select6(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.orderByDesc("id");
    userMapper.selectList(wrapper).forEach(System.out::println );
}
QueryWrapper

allEq 全部匹配 .allEq(Map)
eq .eq(“name”,“value”) -> name = value
ne .ne(“name”,“value”) -> name <> value
gt .gt(“age”,10) -> age >10
ge .ge(“age”,10) -> age >=10
lt .lt(“age”,10) -> age < 10
le .le(“age”,10) -> age <= 10
between 属于ab之间 .between(“age”,a,b)
notBetween 不属于ab之间 ,notBetween(“age”,a,b)
like .like(“name”,“kba”) -> name like “%kba%”
notLike .notlike(“name”,“kba”) -> name not like “%kba%”
likeLeft .likeLeft(“name”,“kba”) -> name like “%kba”
likeRight .likeRight(“name”,“kba”) -> name like “kba%”
notLikeLeft .notlikeLeft(“name”,“kba”) -> name like “%kba”
notLikeRight .notlikeRight(“name”,“kba”) -> name like “kba%”
isNull .isNull(“name”) -> name is null
isNotNull isNotNull(“name”) -> name is not null
in in(“age”,{11,12,13}) -> age in (11,12,13)
notIn notIn(“age”,{11,12,13}) -> age not in (11,12,13)
inSql sql
notInSql
groupBy .group(“gender”,“id”) --> group by name,id
orderByAsc .orderByAsc(“id”) --> oder by id Asc
orderByDesc .orderByDesc(“id”) --> oder by id Desc
orderBy .orderBy(“id”) --> oder by id
or .eq(“age”,1).or().eq(“name”,“kba”) --> age = 1 or name = “kba”
and .eq(“age”,1).and().eq(“name”,“kba”) --> age = 1 and name = “kba”
nested
apply
last
exists
notExists

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值