MyBatis-Plus 学习笔记(狂神)

本文详细介绍了如何使用MyBatis-Plus进行简单的CRUD操作,包括环境搭建、创建数据库表、数据插入与删除、实体类与Mapper的创建。此外,还探讨了MyBatis-Plus的高级特性,如自动填充字段(创建时间和更新时间)、乐观锁机制、分页查询、条件构造器以及代码生成器的使用。通过实例展示了如何利用MyBatis-Plus简化数据库操作,提升开发效率。
摘要由CSDN通过智能技术生成

概述

自动完成简单crud,进行简化操作

快速入门

环境搭建

创建数据库

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)
);


DELETE FROM user;

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');

先创建一个简单的SpringBoot项目

导入需要的依赖(建议mybatis和mybatis-plus不要一起使用,可能有版本冲突)

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

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

连接数据库

spring.datasource.url=jdbc:mysql://localhost:3366/mybatis_plus
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private Long id;
    private String name;
    private int age;
    private String email;

}

创建Mapper,自动生成了简单的crud操作

//注入到容器中
@Repository
public interface userMapper extends BaseMapper<User> {

}

在测试类中测试

    @Autowired
    private userMapper userMapper;

    @Test
    void contextLoads() {
        List<User> userList = userMapper.selectList(null);
        for (User user : userList) {
            System.out.println(user);
        }
    }

配置日志

#配置日志 默认自带日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

CRUD扩展内容

插入操作中主键生成策略

    @Test
    public void test(){
        User user = new User();
        user.setName("小米");
        user.setAge(3);
        user.setEmail("2621");
        userMapper.insert(user);
    }

 没有设置,会有默认的全局唯一id,即在id属性上加

public class User {

    //@TableId("IdType.ID_WORKER") //默认通过雪花算法设置全局唯一的id
    private Long id;
    private String name;
    private int age;
    private String email;

}

分布式系统唯一id生成:https://www.cnblogs.com/haoxinyue/p/5208136.html
雪花算法
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一!

 更新操作

    @Test
    public void UpdateTest(){
        User user = new User();
        user.setId(6L);
        user.setName("小米2");
        user.setAge(4);
        user.setEmail("26213025");
        userMapper.updateById(user);
    }

通过updateById方法修改内容,传递的参数是user对象,会根据设置的值,动态创建修改语句,就如不设置Email,修改时就不会修改Email

自动填充功能

概述,在开发中类似时间的的操作,如某事件创建或者修改的时间需要保存下来,手动去设置比较麻烦,mybatis-plus提供了自动填充的功能

首选在数据库创建字段 create_time 和 update_time

在实体类中写入,并标记填充字段

public class User {

  // @TableId("IdType.ID_WORKER") //默认通过雪花算法设置全局唯一的id
    private Long id;
    private String name;
    private int age;
    private String email;

  // 注意!这里需要标记为填充字段
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

}

标记字段的解释

public enum FieldFill {
    /**
     * 默认不处理
     */
    DEFAULT,
    /**
     * 插入填充字段
     */
    INSERT,
    /**
     * 更新填充字段
     */
    UPDATE,
    /**
     * 插入和更新填充字段
     */
    INSERT_UPDATE
}

填充的方式

MyBatis-Plus的版本3.3.0之下的是如下操作

@Slf4j
@Component
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);
    }
}

MyBatis-Plus的版本3.3.0及以上

 官网连接https://mp.baomidou.com/guide/auto-fill-metainfo.html(中国人写的,通俗易懂)

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
        // 或者
        this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
        // 或者
        this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
        // 或者
        this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
        // 或者
        this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
    }
}

之后进行插入或者修改操作时,会自动填充好相应字段。

乐观锁

乐观锁:顾名思义就是十分乐观,总是认为不会出现问题,做什么事务都不上锁,如果出现了问题,再次尝试更新值测试

悲观锁:顾名思义十分悲观,总是认为会出问题,做什么都加上锁,再去操作

当要更新一条记录的时候,希望这条记录没有被别人更新

乐观锁的实现方式

取出记录时,获取版本号

更新时,带上这个版本号

执行更新时,set version =  new version where version = oldversion

如果version不对,就更新失败

实现方式

user类添加字段

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

 配置类

@MapperScan("com.mapper")
@EnableTransactionManagement   //自动配置事务
@Configuration
public class MybatisPlusConfig {
    /**
     * 旧版
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

    /**
     * 新版
     */
//    @Bean
//    public MybatisPlusInterceptor mybatisPlusInterceptor() {
//        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
//        return mybatisPlusInterceptor;
//    }
}

测试,在更新操作中sql语句中version会加一,在版本号还是查询时版本号时,及数据没有被其他人修改过

    //测试乐观锁
    @Test
    public void testOptimisticLocker(){
        User user = userMapper.selectById(1l);
        user.setName("xiaoming");
        user.setAge(16);
        userMapper.updateById(user);
    }

    //测试乐观锁
    @Test
    public void testOptimisticLocker2(){
        //模拟并发,测试乐观锁
        User user = userMapper.selectById(1l);
        user.setName("xiaoming1");
        user.setAge(16);
        //第二者插入
        User user2 = userMapper.selectById(1l);
        user2.setName("xiaoming2");
        user2.setAge(16);
        //修改成功
        userMapper.updateById(user2);
        //修改失败
        userMapper.updateById(user);
    }

查询操作

    //查询操作
    @Test
    public void selectTest(){
        //查询全部
//        userMapper.selectList(null);
        //通过id查询一个
//        userMapper.selectById();
        //通过id查询多个
        userMapper.selectBatchIds(Arrays.asList(1l,2l));
        //条件查询   在查询时将map中的值作为条件
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","Sandy");
        map.put("age",21);

        List<User> userList = userMapper.selectByMap(map);
        for (User user : userList) {
            System.out.println(user);
        }
    }

分页插件

配置分页插件  MybatisPlusConfig中


    // 旧版  分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

    // 最新版  分页
//    @Bean
//    public MybatisPlusInterceptor mybatisPlusInterceptor() {
//        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
//        return interceptor;
//    }
    //测试分页
    @Test
    public void PaginationTest(){
        //参数一 当前页   参数二 页面大小    根据sql可以看出也是通过limit实现
        // SELECT id,name,age,email,version,create_time,update_time FROM user LIMIT 0,5
        Page<User> page = new Page<>(1,5);
        IPage<User> userIPage = userMapper.selectPage(page, null);
        long pages = userIPage.getPages();
        System.out.println("总页数"+pages);
        List<User> records = userIPage.getRecords();
        for (User user : records) {
            System.out.println(user);
        }
    }

删除操作

方法与查询类似

    //测试删除
    @Test
    public void DeleteTest(){
        //传入list集合批量删除
//        userMapper.deleteBatchIds(Arrays.asList(1l,2l));
        //通过id删除
//        userMapper.deleteById(3l);
        //通过map传入条件删除
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","小米2");
        userMapper.deleteByMap(map);
    }

逻辑删除

物理删除:从数据库中删除

逻辑删除:在数据库中没有删除,而是通过一个变量让他失效

首选在数据库中添加字段deleted并设置默认为0

注意不要将字段名设置成delete,这将在sql语句中当成关键字导致sql出错

在实体类中添加字段和注解

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

配置

#配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

添加组件 

3.3版本以上不需要此组件,只需要上面两个步骤

    // 逻辑删除组件!
    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }

测试 看出实际走的是update操作

userMapper.deleteById(5L);


==>  Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0 
==> Parameters: 5(Long)
<==    Updates: 1

性能分析插件(3.2版本后弃用)

 

条件构造器 

通过wrapper,设置需要的条件,与map类似,区别是wrapper是链式书写,内置许多条件方法

@SpringBootTest
public class WrapperTest {

    @Autowired
    private userMapper userMapper;

    @Test
    public void test1(){
        //通过wrapper设置条件,编写单表的带条件sql
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
                .ge("age",10);
        userMapper.selectList(wrapper);
    }


    @Test
    public void test2(){
        //通过wrapper设置条件,编写单表的带条件sql
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //==>  Preparing: SELECT id,name,age,email,version,deleted,create_time,update_time FROM user WHERE deleted=0 AND name = ? AND age >= ?
        //==> Parameters: xiaoming2(String), 10(Integer)
        wrapper.eq("name","xiaoming2")
                .ge("age",10);
        userMapper.selectOne(wrapper);  //查询一个
    }

    @Test
    public void test3(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",10,20);
        userMapper.selectCount(wrapper);
    }

    @Test
    public void test4(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //==>  Preparing: SELECT id,name,age,email,version,deleted,create_time,update_time FROM user WHERE deleted=0 AND name NOT LIKE ? AND email LIKE ?
        //==> Parameters: %2%(String), 26%(String)
        wrapper.notLike("name","2")
                .likeRight("email",26);  //like的右边,即以26开始
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        for (Map<String, Object> map : maps) {
            System.out.println(map);
        }
    }

    @Test
    public void test5(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //SELECT id,name,age,email,version,deleted,create_time,update_time FROM user
        // WHERE deleted=0 AND id IN (select id from user where id<3)
        wrapper.inSql("id","select id from user where id<3");
        userMapper.selectObjs(wrapper);
    }

    @Test
    public void test6(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //排序  升序  可以加入多个参数
        wrapper.orderByAsc("id");
        userMapper.selectObjs(wrapper);
    }
}

代码自动生成器

导入依赖

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
<!--        velocity模板引擎,mybatis-plus 代码生成器需要-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.0</version>
        </dependency>
        <!--        swagger依赖-->
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>3.0.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;

public class KuangCode {
    public static void main(String[] args) {
            // 需要构建一个 代码自动生成器 对象
            AutoGenerator mpg = new AutoGenerator();
            // 配置策略
            // 1、全局配置
            GlobalConfig gc = new GlobalConfig();
            String projectPath = System.getProperty("user.dir");
            gc.setOutputDir(projectPath+"/src/main/java");
            gc.setAuthor("smile");
            gc.setOpen(false);
            gc.setFileOverride(false); // 是否覆盖
            gc.setServiceName("%sService"); // 去Service的I前缀
            gc.setIdType(IdType.ID_WORKER);
            gc.setDateType(DateType.ONLY_DATE);
            gc.setSwagger2(true);
            mpg.setGlobalConfig(gc);

            //2、设置数据源
            DataSourceConfig dsc = new DataSourceConfig();
            dsc.setUrl("jdbc:mysql://localhost:3366/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
            dsc.setDriverName("com.mysql.jdbc.Driver");
            dsc.setUsername("root");
            dsc.setPassword("123456");
            dsc.setDbType(DbType.MYSQL);
            mpg.setDataSource(dsc);

            //3、包的配置
            PackageConfig pc = new PackageConfig();
            pc.setModuleName("blog");  //模板名
            pc.setParent("com");
            pc.setEntity("pojo");
            pc.setMapper("mapper");
            pc.setService("service");
            pc.setController("controller");
            mpg.setPackageInfo(pc);

            //4、策略配置
            StrategyConfig strategy = new StrategyConfig();

            strategy.setInclude("user"); // 设置要映射的表名

            strategy.setNaming(NamingStrategy.underline_to_camel);
            strategy.setColumnNaming(NamingStrategy.underline_to_camel);
            strategy.setEntityLombokModel(true); // 自动lombok;
            strategy.setLogicDeleteFieldName("deleted");

            // 自动填充配置
            TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
            TableFill gmtModified = new TableFill("update_time", FieldFill.INSERT_UPDATE);
            ArrayList<TableFill> tableFills = new ArrayList<>();
            tableFills.add(gmtCreate);
            tableFills.add(gmtModified);
            strategy.setTableFillList(tableFills);

            // 乐观锁
            strategy.setVersionFieldName("version");
            strategy.setRestControllerStyle(true);
            strategy.setControllerMappingHyphenStyle(true); //localhost:8080/hello_id_2
            mpg.setStrategy(strategy);
            mpg.execute(); //执行
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值