MyBatis-Plus详解

一、Mybatis-Plus

MyBatis-Plus官网
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
在这里插入图片描述

1.Mybatis-plus快速入门

(1)创建数据库,创建相关的表

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, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
#真实开发中,version(乐观锁)、delete(逻辑删除)、gmt_create、gmt_modified

(2)使用 Spring Initializer快速初始化maven工程,添加相关的依赖

<dependencies>
    <!--mybatis-plus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>
    <!--springboot-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!--mysql数据库驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!--单元测试-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

(3)配置文件application.properties(数据库连接、日志等)

#1.数据库连接
spring.datasource.username=root
spring.datasource.password=12345678
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=UTF-8&useSSL=FALSE&serverTimezone=UTC&useOldAliasMetadataBehavior=true
#2.配置日志信息
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

(4)创建实体类,标注相关的注解

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    
    
    private Integer id;
    private String name;
    private Integer age;
    private String email;
}

(5)创建mapper接口,继承BaseMapper< T >接口

//代表持久层,此处的泛型T换成子类的实体类即可
@Repository
public interface UserMapper extends BaseMapper<User> {
    
    
}

(6)在主启动类上标注注解@MapperScan(“对应的mapper接口的类路径”)
(7)测试

@SpringBootTest
class MybatisPlusApplicationTests {
    
    
    @Autowired
    private UserMapper userMapper;
    @Test
    void contextLoads() {
    
    
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

在这里插入图片描述

二、CRUD扩展操作

1.插入操作

// 测试插入
@Test
public void testInsert(){
    
    
    User user = new User();
    //user.setId(6);
    user.setName("小王");
    user.setAge(2);
    user.setEmail("[email protected]");
    int result = userMapper.insert(user);// 无法帮我们自动生成id
    System.out.println(result); // 受影响的行数0
}

版本更新较快,雪花算法自动生成id已经失效,没有设置id,此时插入失败。将id设置属性值再次测试,插入成功。
在这里插入图片描述

2.主键生成策略

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

设置主键自增:
(1)实体类User的主键字段上@TableId(type = IdType.AUTO)
(2)对应数据库表设置主键自增,并设置初始值
在这里插入图片描述
(3)不设置主键,插入成功

// 测试插入
@Test
public void testInsert(){
    
    
    User user = new User();
    user.setName("小王");
    user.setAge(2);
    user.setEmail("[email protected]");
    int result = userMapper.insert(user);//自动生成id后插入成功
    System.out.println(user);//插入的记录
    System.out.println(result); // 受影响的行数
}

在这里插入图片描述
IdType源码解释

public enum IdType {
    
    
    AUTO(0),	//数据库id自增
    NONE(1),	//未设置主键
    INPUT(2),	//手动输入
    ASSIGN_ID(3),	//默认的全局唯一id
    ASSIGN_UUID(4),	//全局唯一id UUID
    ID_WORKER_STR(5); //ID_WORKER 字符串表示法
}

3.更新操作

@Test
public void testUpdate(){
    
    
    User user = new User();
    user.setId(6L);
    user.setName("小吕");
    user.setAge(4);
    //updateById(User user)方法的参数是一对象
    int result = userMapper.updateById(user);
    System.out.println(result);
}

根据id进行的更新操作,更新成功。
在这里插入图片描述

4.自动填充

阿里巴巴开发手册:所有的数据库表:gmt_create(创建)、gmr_modified(更新)几乎所有的表都要配置上!而且需要自动化!
方式一:数据库级别(实际中不允许)
(1)在表中新增字段 create_time, update_time
在这里插入图片描述
(2)同步对应的User实体类添加新增的属性

private Date createTime;
private Date updateTime;

(3)再次更新查看结果即可
在这里插入图片描述
方式二:代码级别
(1)删除数据库的默认值
在这里插入图片描述
(2)在User实体类的字段上添加注解

//字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;

(3)编写处理器处理注解

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    
    @Override
    public void insertFill(MetaObject metaObject) {
    
    
        log.info("insert Fill start...");
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
    @Override
    public void updateFill(MetaObject metaObject) {
    
    
        log.info("update Fill start...");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

(4)测试插入、更新操作,可以看到也实现了同样的功能。(此处若和电脑系统时间不一致,应该在application.properties中配置url时配置时区)
在这里插入图片描述

5.乐观锁

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

当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
① 取出记录时,获取当前 version
② 更新时,带上这个 version
③ 执行更新时, set version = newVersion where version = oldVersion
④ 如果 version 不对,就更新失败

(1)给数据库表增加version字段
在这里插入图片描述
(2)对应的实体类增加属性

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

(3)配置类注册组件

@Configuration
@MapperScan("按需修改")
public class MyBatisPlusConfig {
    
    
    /**
     * 旧版
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    
    
        return new OptimisticLockerInterceptor();
    }

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

(4)测试乐观锁

//乐观锁执行成功,单线程
@Test
public void testOptimisticLocker(){
    
    
    User user = userMapper.selectById(1L);
    user.setName("小王");
    user.setAge(3);
    int result = userMapper.updateById(user);
    System.out.println(result);
}

//乐观锁执行失败,模拟多线程插队
@Test
public void testOptimisticLocker02(){
    
    
    User user = userMapper.selectById(1L);
    user.setAge(15);
    user.setName("张扬");
    //模拟另一个线程执行了插队操作
    User user2 = userMapper.selectById(1L);
    user2.setName("沉默");
    user2.setAge(5);
    int result = userMapper.updateById(user2);
    System.out.println(result);
}

在这里插入图片描述

6.查询操作

//1.单条记录查询SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id=? 
@Test
public void testSelectById(){
    
    
    User user = userMapper.selectById(1L);
    System.out.println(user);
}
//2.多条记录查询SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id IN ( ? , ? , ? ) 
@Test
public void testSelectBatchIds(){
    
    
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    users.forEach(System.out::println);
}
//3.条件查询SELECT id,name,age,email,create_time,update_time,version FROM user WHERE name = ? AND age = ? 
@Test
public void test(){
    
    
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","沉默");
    map.put("age",5);
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

7.分页查询

(1)配置分页插件拦截器

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

(2)测试分页查询

//分页查询
@Test
public void testPage(){
    
    
    //参数1:当前页 参数2:页面大小
    Page<User> page = new Page<>(1,5);
    //参数1:page对象 参数2:条件选择器
    userMapper.selectPage(page, null);
    page.getRecords().forEach(System.out::println);
    System.out.println(page.getTotal());
}

在这里插入图片描述

8.删除操作

//1.删除单条记录
@Test
public void testDeleteById(){
    
    
    int result = userMapper.deleteById(6L);
    System.out.println(result);
}
//2.删除多条记录
@Test
public void testDeleteBatchIds(){
    
    
    int result = userMapper.deleteBatchIds(Arrays.asList(7, 8, 9));
    System.out.println(result);
}
//3.条件删除
@Test
public void testDeleteByMap(){
    
    
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","沉默");
    map.put("age",5);
    int result = userMapper.deleteByMap(map);
    System.out.println(result);
}

9.逻辑删除(假删除)

物理删除:从数据库中直接移除
逻辑删除:在数据库中没有被移除,而是通过一个变量来让他失效!deleted = 0 => deleted = 1
删除: update user set deleted=1 where id = 1 and deleted=0
查找: select id,name,deleted from user where deleted=0
(1)数据库表中增加字段
在这里插入图片描述
(2)对应User实体类上添加属性

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

(3)配置文件配置逻辑删除

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

(4)配置逻辑删除

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

(5)测试删除操作

@Test
public void testDelete(){
    
    
    int res = userMapper.deleteById(3L);
    System.out.println(res);
}

可以看到实际执行的是update操作,数据库中的记录还是存在的。在查询时会自动过滤逻辑删除的记录。
在这里插入图片描述

三、Wrapper条件查询器

条件构造器

@SpringBootTest
public class WrapperTest {
    
    
    @Autowired
    private UserMapper userMapper;
    @Test
    void contextLoads() {
    
    
        //查询name不为空的用户,并且邮箱不为空的用户,年龄大于12
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
                .isNotNull("email")
                .eq("name","Tom");
        userMapper.selectList(wrapper).forEach(System.out::println); //和我们刚刚学习的map对比一下
    }
    @Test
    void test2(){
    
    
        //查询名字Chanv
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name", "Chanv");
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }
    @Test
    void test3(){
    
    
        //查询年龄在19到30岁之间的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age", 19, 30); //区间
        Integer count = userMapper.selectCount(wrapper);
        System.out.println(count);
    }
    //模糊查询
    @Test
    void test4(){
    
    
        //查询年龄在19到30岁之间的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //左和右
        wrapper.notLike("name", "b")
                .likeRight("email", "t");
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }
    @Test
    void test5(){
    
    
        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 test6(){
    
    
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //通过id进行排序
        wrapper.orderByDesc("id");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
}

四、代码生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
1.引入相关的依赖

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

2.配置相关的策略

//代码生成器
public class Code {
    
    
    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("wds");
        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:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("12345678");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        //3、包的配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");
        pc.setParent("com.chanv");
        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 createTime = new TableFill("create_time", FieldFill.INSERT);
        TableFill updateTime = new TableFill("update_time", FieldFill.UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(createTime);
        tableFills.add(updateTime);
        strategy.setTableFillList(tableFills);
        //乐观锁
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);     //localhost:8080/hello_id_2
        mpg.setStrategy(strategy);

        mpg.execute();  //执行代码构造器
    }
}

更多的技术大家可以去b站学习狂神说:【狂神说Java】MyBatisPlus最新完整教程通俗易懂

猜你喜欢

转载自blog.csdn.net/weixin_46081857/article/details/124110912