MybatisPlus笔记整理

1.入门

官方文档

使用MybatisPlus可以节省大量代码

1、创建数据库

2、创建user表

DROP TABLE IF EXISTS user;

CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);

INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

3、编写项目,初始化项目SpringBoot

4、导入依赖

注意:不要同时导入Mybatis和MybatisPlus

<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>
<!--mybatisplus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>

5、连接数据库

编写application.properties文件

#数据库连接配置
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#配置日志(控制台输出)
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

6、传统:pojo-dao(连接mybatis、配置mapper.xml文件)-service-controller

​ 现在:

  • pojo实体类:

    package com.kuang.dao;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    //lombok插件
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private Long id;	//数据库主键
        private String name;
        private Integer age;
        private String email;
    }
    
  • mapper接口:

    package com.kuang.mapper;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.kuang.dao.User;
    import org.springframework.stereotype.Repository;
    
    @Repository     //代表持久层
    public interface UserMapper extends BaseMapper<User> {
    
        //所有的CRUD操作已经编写完成
        //不在需要像以前的配置一大堆文件,比如MybatisUtils,UserMapper.xml等等
    }
    

    编写MybatisplusApplication文件

    @MapperScan("com.kuang.mapper")     //扫描mapper文件夹
    @SpringBootApplication
    public class MybatisplusApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MybatisplusApplication.class, args);
        }
    
    }
    
  • 使用测试:

    @SpringBootTest
    class MybatisplusApplicationTests {
    
        //继承了BaseMapper,所有的方法都来自父类BaseMapper
        //也可以编写自己的扩展方法
        @Autowired
        private UserMapper userMapper;
    
        @Test
        void contextLoads() {
            //查询全部用户
            List<User> users = userMapper.selectList(null);      //wrapper是条件构造器,先取值null
            users.forEach(System.out::println);
       }
    }
    

    查看BaseMapper,它包含了许多CRUD方法

    public interface BaseMapper<T> {
        int insert(T var1);
    
        int deleteById(Serializable var1);
    
        int deleteByMap(@Param("cm") Map<String, Object> var1);
    
        int delete(@Param("ew") Wrapper<T> var1);
    
        int deleteBatchIds(@Param("coll") Collection<? extends Serializable> var1);
    
        int updateById(@Param("et") T var1);
    
        int update(@Param("et") T var1, @Param("ew") Wrapper<T> var2);
    
        T selectById(Serializable var1);
    
        List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> var1);
    
        List<T> selectByMap(@Param("cm") Map<String, Object> var1);
    
        T selectOne(@Param("ew") Wrapper<T> var1);
    
        Integer selectCount(@Param("ew") Wrapper<T> var1);
    
        List<T> selectList(@Param("ew") Wrapper<T> var1);
    
        List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> var1);
    
        List<Object> selectObjs(@Param("ew") Wrapper<T> var1);
    
        IPage<T> selectPage(IPage<T> var1, @Param("ew") Wrapper<T> var2);
    
        IPage<Map<String, Object>> selectMapsPage(IPage<T> var1, @Param("ew") Wrapper<T> var2);
    }
    

7、测试结果
在这里插入图片描述

附项目结构图:
在这里插入图片描述

思考:

  • SQL我们并没有写,MybatisPlus帮我们写了SQL。
  • 方法哪里来的?MybatisPlus也帮我们写了。

2、插入测试

@Test
public void testInsert(){
    User user = new User();
    user.setName("小呱");
    user.setAge(18);
    //user.setId((long) 123);		这里先不设置主键Id,运行会发现MybatisPlus自动帮你生成了Id
    user.setEmail("123@qq.com");

    int result = userMapper.insert(user);
    System.out.println(result);		//返回受影响的行数
    System.out.println(user);
}

结果:
在这里插入图片描述

这里在插入数据时并没有给id赋值,但是可以从运行结果可以看出,MP给我们赋了值

2.1、主键生成策略

推荐一篇博客:分布式系统唯一ID生成方案汇总

雪花算法(Snowflake)

Snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。

其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。

几乎可以保证全球唯一

2.2、主键自增

  • 实体类字段上增加注解

    @TableId(type = IdType.AUTO)

    在这里插入图片描述

  • 数据库字段一定要是自增
    在这里插入图片描述

加上注解和自增设置完成后再次运行,会发现ID自动自增:
在这里插入图片描述

3、更新测试

3.1、基本测试

@Test
public void testUpdate(){
    User user = new User();
    //通过条件自动拼接动态SQL
    user.setId(5L);
    user.setName("小黄");
    user.setAge(36);
    int result = userMapper.updateById(user);	//根据Id更新数据
    System.out.println(result);
}

运行结果:
在这里插入图片描述

MybatisPlus可以通过条件自动拼接动态SQL

在这里插入图片描述

3.2、自动填充

第一种方法:数据库级别(不推荐)

1、在表中新增字段create_timeupdate_time(默认值设置为CURRENT_TIMESTAMP,图片里忘记设置了)

在这里插入图片描述

2、再次测试插入方法,需要先把实体类同步

private Date createTime;
private Date updateTime;

3、运行结果:
在这里插入图片描述

第二张方法:代码级别

1、删除数据库的默认值、更新操作
在这里插入图片描述

2、在实体类字段属性上增加注解

@TableField(fill = FieldFill.INSERT)
private Date createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

3、编写处理器来处理这个注解(新建com.kuang.handler.MyMetaObjectHandler )

package com.kuang.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;

@Slf4j
@Component      //一定不要忘记把处理器加到IOC容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill...");
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

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

4、测试插入

5、测试更新

3.3、乐观锁

乐观锁:它总是认为不会出现问题,无论干什么都不去上锁;如果出现了问题,就再次更新值测试。

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

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
1、先查询,获取版本号,假设version = 1
-- A线程
update `user` set name = "Jack",version = version + 1
where id = 2 and version = 1

-- B线程抢先完成,这个时候version=2,会导致A修改失败
update `user` set name = "Tom",version = version + 1
where id = 2 and version = 1

测试MybatisPlus中的乐观锁插件

1、给数据库中增加version字段

在这里插入图片描述

2、实体类加对应的字段

@Version		//乐观锁Version注解
private Integer version;

3、注册组件

@MapperScan("com.kuang.mapper")     //扫描mapper文件夹,将MybatisplusApplication中的MapperScan移到此处
@EnableTransactionManagement
@Configuration		//配置类
public class MybatisPlusCongif{
    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        
        return new OptimisticLockerInterceptor();
    }
}

附:
在这里插入图片描述

4、测试

测试乐观锁成功(单线程)

@Test
public void testOptimisticLocker(){
    //查询用户信息
    User user = userMapper.selectById(1L);
    //修改用户信息
    user.setName("newMan");
    user.setEmail("666@qq.com");
    //执行更新操作
    userMapper.updateById(user);
}

运行结果:
在这里插入图片描述

测试乐观锁失败(多线程)

@Test
public void testOptimisticLocker02(){
    
    //线程1
    User user = userMapper.selectById(1L);
    user.setName("newMan");
    user.setEmail("666@qq.com");
    
    //线程2	模拟另外一个线程执行了插队操作
    User user2 = userMapper.selectById(1L);
    user2.setName("newMan222");
    user2.setEmail("222@qq.com");
    userMapper.updateById(user2);
    
    //线程1虽然设置了值,但是被线程2插队,导致线程1的执行会失败
    
    userMapper.updateById(user);	//如果没有乐观锁,就会覆盖插队线程2的值
}

运行结果:
在这里插入图片描述

4、查询操作

4.1、基本查询

//查询一个用户
@Test
public void testSelectById(){
     User user = userMapper.selectById(1L);
    System.out.println(user);
}

运行结果:
在这里插入图片描述

//一次查询多个用户
@Test
public void testSelectById(){
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1,2,3));
    users.forEach(System.out::println);
}

运行结果:
在这里插入图片描述

//条件查询map
@Test
public void testSelectByIds(){
    HashMap<String,Object> map = new HashMap<>();
    
    //自定义查询
    map.put("name","Jack");
    map.put("age",20);
    
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

运行结果:
在这里插入图片描述

4.2、分页查询

分页插件

@MapperScan("com.kuang.mapper")     //扫描mapper文件夹,将MybatisplusApplication中的MapperScan移到此处
@EnableTransactionManagement
@Configuration		//配置类
public class MybatisPlusCongif{
    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        
        return new OptimisticLockerInterceptor();
    }
    
    //注册分页
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}  

测试

@Test
public void testPage(){
    //参数一:当前页
    //参数二:页面大小
    
    Page<User> page = new Page<>(1,5);
    userMapper.selectPage(page,null);
    page.getRecords().forEach(System.out::println);
    System.out.println(page.getTotal());
}

运行结果:
第一页:
在这里插入图片描述
第二页:
在这里插入图片描述

5、删除操作

5.1、基本删除

//删除一个
@Test
public void testDeleteById(){
    userMapper.deleteById(1L);
}

运行结果:
在这里插入图片描述

//批量删除
@Test
public void testDeleteBatchIds(){
    userMapper.deleteBatchIds(Arrays.asList(2L,3L));
}

在这里插入图片描述

//通过map删除
@Test
public void testDeleteMap(){
    HashMap<String,Object> map = new HashMap<>();
    
    //自定义查询
    map.put("name","Jack");
    map.put("age",20);
    
    userMapper.deletaByMap(map);
}

运行结果:
在这里插入图片描述

5.2、逻辑删除

物理删除:从数据库中直接移除

逻辑删除:在数据库中没有被移除,而是通过一个变量来让它失效!deleted = 0 ==> deleted = 1

1、在数据表中增加一个字段deleted,默认值为0
在这里插入图片描述

2、实体类中增加属性

@TableLogic		//逻辑删除注解
private Integer deleted;

3、逻辑删除组件

@Bean
public ISqlInjector sqlInjector(){
    return new LogicSqlInjector();
}

4、配置文件(application.properties)

#配置逻辑删除,默认未删除时deleted的值为0
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

5、执行一个删除操作

记录依旧在数据库,然是deleted值已经发生变化了

在这里插入图片描述
在这里插入图片描述

现在再次执行查询,发现已经查询不到刚刚删除的用户

在这里插入图片描述

6、条件查询器Wapper

官方文档Wapper介绍

测试一

@Test
void test01(){
    //查询name不为空的用户,并且邮箱不为空的,年龄大于12
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper
            .isNotNull("name")
            .isNotNull("email")
            .ge("age",12);

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

运行结果:
在这里插入图片描述

测试二

@Test
void test02(){
    //查询name = Jack的数据
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper
            .eq("name","Jack");
    User user = userMapper.selectOne(wrapper);		//查询一个数据,出现多个结果使用List或者map
    System.out.println(user);
}

运行结果:
在这里插入图片描述

测试三

@Test
void test03(){
    //查询年龄在20~30岁之间的用户
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper
            .between("age",10,20);      //区间10~20
    Integer count = userMapper.selectCount(wrapper);      //查询结果数
    System.out.println(count);

}

运行结果:
在这里插入图片描述

测试四

//模糊查询
@Test
void test04(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper
            .notLike("name","M")        //name里不包含“M”
            .likeRight("email","1");    //email以“1”开头
    List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
    maps.forEach(System.out::println);
}

运行结果:
在这里插入图片描述

测试五

@Test
void test05(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //id在子查询中查出来
    wrapper
            .inSql("id","select id from user where id<3");
    List<Object> objects = userMapper.selectObjs(wrapper);
    objects.forEach(System.out::println);
}

运行结果:
在这里插入图片描述

测试六

@Test
void test06(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //通过id进行降序排列
    wrapper
            .orderByDesc("id");
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

运行结果:
在这里插入图片描述

注:本笔记来源自学B站up主遇见狂神说后自己整理得来,up主十分良心,疯狂安利!

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值