MyBatis-plus快速入门

Mybatis-plus快速入门

官网及文档:https://mp.baomidou.com/

数据库配置

数据库以官方例子为例
现有一张 User 表,其表结构如下:
在这里插入图片描述

其对应的数据库 Schema 脚本如下:

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

其对应的数据库 Data 脚本如下:

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项目

引入依赖

<!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--mybatis-plus驱动-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>

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

项目配置

这里使用ymal进行配置

spring:
  datasource:
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8
# 配置日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

编码

pojo
这里使用lombok编写,没有lombok要下载插件

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

mapper
要继承BaseMapper

@Repository
public interface UserMapper extends BaseMapper<User> {
    //继承BaseMapper<T> 所有的CRUD已经编写完成
}

测试

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

    }

}

UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件

结果

在这里插入图片描述
配置完日志
在这里插入图片描述

CRUD扩展

插入测试

@Test
    //测试插入
    public void testInsert(){
        User user = new User();
        user.setName("张三");
        user.setAge(18);
        user.setEmail("123456@qq.com");
        int result = userMapper.insert(user);
        System.out.println(result);
        System.out.println(user);
    }

注意:这里没有写填写id
在这里插入图片描述

主键生成策略

分布式系统唯一ID生成方法汇总:https://www.cnblogs.com/haoxinyue/p/5208136.html
通过结果我们可以发现 id会自动填写
通过结果我们可以发现这里默认的是ID_WORKER 全局唯一ID

全局唯一ID

实现的算法为雪花算法
雪花算法
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。雪花算法支持的TPS可以达到419万左右(2^22*1000)。
这里使用的mybatis-plus版本为3.0.5 新版本应该对应ASSIGN_ID
在这里插入图片描述

我们在UserMapper上 对id 添加主键注解
在这里插入图片描述
点开@TableId源码可以看到以下主键自增策略
在这里插入图片描述

主键自增

1.添加注解
在这里插入图片描述
2.数据库字段一定是要自增
在这里插入图片描述
3.测试
再次插入
在这里插入图片描述
发现主键生成策略已是自增
在这里插入图片描述

更新测试

@Test
    //测试更新
    public void testUpdate(){
        User user = new User();
        user.setName("李四");
        user.setId(5L);
        user.setEmail("123456@qq.com");
        int result = userMapper.updateById(user);//注意参数为User类型
        System.out.println(result);
        System.out.println(user);

    }

结果
在这里插入图片描述
在这里插入图片描述
我们再次修改 这次修改加入年龄
在这里插入图片描述
我们可以发现sql是动态帮我们配置的

自动填充

像创建时间、修改时间,这些操作一般都是自动化完成的,我们不希望手动更新
阿里巴巴开发手册规定:所有的数据库表中都要有:gmt_create gmt_modified 且需要自动化

方式一 修改数据库 (工作中一般不允许改动数据库)

  1. 在表中新增gmt_create gmt_modified
    在这里插入图片描述
    2.更新实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Date gmtCreate;
    private Date gmtModified;
}

3.再次更新
在这里插入图片描述

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

方式二 代码

1.先把默认值和更新去掉在这里插入图片描述
2.实体类上增加注解

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    //字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date gmtCreate;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmtModified;

3.编写处理器处理这个注解

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

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

4.测试
插入:
在这里插入图片描述
修改:
在这里插入图片描述

乐观锁

乐观锁:顾名思义十分乐观,认为不会出现问题,不上锁,如果出现了问题则再次更新值测试
悲观锁:顾名思义十分悲观,认为总会出现问题,无论干什么都要先上锁,再去操作

在这里插入图片描述
举个例子:

乐观锁:先查询 获得版本号-- version = 1
--A
update user set name = "张三" , version = version + 1
where id = 2 and version = 1 
--B B线程抢先完成,这个时候version = 2, 会导致A线程修改失败!
update user set name = "张三" , version = version + 1
where id = 2 and version = 1 

mybatis-plus中乐观锁插件

1.给数据库中添加version字段
在这里插入图片描述
2.修改实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @Version//代表这个是一个乐观锁
    private Integer version;
    //字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date gmtCreate;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmtModified;

3.注册组件
注意新版本配置不同 以官方文档为准

@MapperScan("com.choi.dao")//可以将Application的Mapper扫描放在配置类里
@EnableTransactionManagement//开启事务
@Configuration//配置类
public class MybatisPlusConfig {
    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
}

4.测试

//测试乐观锁成功
    @Test
    public void testOptimisticLocker(){
        //1.查询用户信息
        User user = userMapper.selectById(1L);
        //2.修改用户信息
        user.setName("王五");
        user.setEmail("123456@qq.com");
        //3.执行更新操作
        userMapper.updateById(user);
    }

在这里插入图片描述

 //测试乐观锁失败
    @Test
    public void testOptimisticLocker2(){
        //这里模拟多线程
        //线程A
        User user1 = userMapper.selectById(1L);
        user1.setName("王五111");
        user1.setEmail("123456@qq.com");

        //B线程
        User user2 = userMapper.selectById(1L);
        user2.setName("王五222");
        user2.setEmail("123456@qq.com");
        //B线程比A先完成
        userMapper.updateById(user2);
        userMapper.updateById(user1);
    }

在这里插入图片描述

查询测试

较为简单 则不放结果

//查询测试
    //按ID查询
    @Test
    public void testSelectById(){
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }
    //多ID查询
    @Test
    public void testSelectBatchId(){
        List<User> userList = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));//传入集合
        userList.forEach(System.out::println);
    }
    // 条件查询 map
    @Test
    public void testSelectByMap(){
        HashMap<String,Object> map = new HashMap<>();
        //自定义查询 map.put("字段名","值")  多个map.put则是多条件查询
        map.put("name","张三");
        map.put("age",20);
        List<User> userList = userMapper.selectByMap(map);
        userList.forEach(System.out::println);
    }

分页查询

分页在网站里面使用的十分之多
1.原始的limit进行分页
2.pageHelper第三方插件
3.mybatis-plus 分页插件

这里使用mybatis-plus分页插件(版本问题可能使用方式不同 具体以官网为准)
1.注册分页插件

 @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        // paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        // paginationInterceptor.setLimit(500);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }
    ------------------------------------------------------------
    //这里我们简化 直接返回即可
    //注册分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

2.直接使用page对象即可

   //分页查询
    @Test
    public void testPage(){
        Page<User> page = new Page<>(1,5);//第一个参数:当前页  第二个参数:页大小
        userMapper.selectPage(page, null);//wrapper先写null

        page.getRecords().forEach(System.out::println);
        System.out.println(page.getTotal());//一共有多少条数据
        System.out.println(page.hasNext());//是否有下一页
        System.out.println(page.hasPrevious());//是否有上一页
        System.out.println(page.getPages());//一共有多少页
        System.out.println(page.getCurrent());//当前是第几页
    }

删除测试

基本删除

//删除测试
    @Test
    public void testDeleteById(){
        userMapper.deleteById(1460137473252642820L);
    }
    //ID批量删除
    @Test
    public void testDeleteBatchId(){
        userMapper.deleteBatchIds(Arrays.asList(1460137473252642819L,1460137473252642818L));
    }
    //通过map删除
    @Test
    public void testDeleteByMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","王五222");
        userMapper.deleteByMap(map);
    }

逻辑删除

物理删除:从数据库中直接移除
逻辑删除:再数据库中没有被移除,而是通过一个变量使他失效 如 deleted = 0 => deleted = 1

管理员可以查看被删除的记录,以防止数据的丢失,类似回收站
测试:
1.在数据库中增加 deleted字段
在这里插入图片描述
2.修改实体类
在这里插入图片描述
3.注册插件
新版本以官网为准

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

yaml

 #配置逻辑删除
  global-config:
    db-config:
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

4.测试
在这里插入图片描述

按ID删除、批量删除和条件删除各执行一次
在这里插入图片描述
结果:
在这里插入图片描述
我们可以看到对应的sql语句也和物理删除不同:
本质走的是更新操作
在这里插入图片描述
我们这是进行一次查询所有信息
我们可以发现对应的查询sql语句也发生了变化
在这里插入图片描述

性能分析插件

我们在平时的开发中,会遇到一些慢sql。
作用:性能分析拦截器,用于输出每条sql语句及其执行的时间
mybatis-plus提供性能分析插件,如果超过这个时间就停止运行
(dev测试环境要在yaml里配置)

spring:
  profiles:
    active: dev

1.导入插件
新版本配置方法以官网为准

//sql执行效率分析插件
    @Bean
    @Profile({"dev","test"})//设置dev test环境开启 保证效率
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(1);//ms 设置sql执行的最大时间,超时则不执行
        performanceInterceptor.setFormat(true);//是否开启格式化支持
        return performanceInterceptor;
    }

2.测试
这里我们执行一个查询所有信息 => 报错
在这里插入图片描述

条件构造器 wrapper

通过官网我们可以看到:
在这里插入图片描述
测试一:

@Test
    void contextLoads() {
        //查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
                .isNotNull("email")
                .ge("age",12);//g:大于 e:等于
        userMapper.selectList(wrapper);//wrapper 对比 map

    }

在这里插入图片描述
测试二:

//查询单个 名字叫Jack
    @Test
    public void test2(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","Jack");
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }

在这里插入图片描述
测试三:
在这里插入图片描述

// 查询年龄20~30的用户有多少个
    @Test
    public void test3(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",20,30);
        Integer count = userMapper.selectCount(wrapper);//查询结果数 
        System.out.println(count);

    }

在这里插入图片描述
测试四:

// 查询年龄20~30的用户有谁
    @Test
    public void test4(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",20,30);
        List<Object> user = userMapper.selectObjs(wrapper);
        user.forEach(System.out::println);
    }

同理 not between用法也类似
测试五

//模糊查询
    @Test
    public void test5(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.like("name","张")
                .notLike("age",1)
                .likeLeft("email","m")//左模糊 %X
                .likeRight("id",1);//右模糊 X%
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }

在这里插入图片描述
测试六:

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

在这里插入图片描述
测试七:

//排序
    @Test
    public void test7(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.orderBy(true,false,"age","id");//参数一:是否要排序 参数二:是否ASC 参数三:字段
        userMapper.selectList(wrapper);
    }

在这里插入图片描述
测试八:

//分组
    @Test
    public void test8(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.select("name","email").groupBy(true,"id");
        List<User> userList = userMapper.selectList(wrapper);
        userList.forEach(System.out::println);
    }

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

代码生成器

最新配置方法以官方为准
1.首先将依赖和MybatisPlusConfig配置好

<!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--mybatis-plus驱动-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
public class MybatisPlusConfig {
    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
    //注册分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
    //逻辑删除
    @Bean
    public ISqlInjector sqlInjector(){
        return new LogicSqlInjector();
    }
    //sql执行效率分析插件
    @Bean
    @Profile({"dev","test"})//设置dev test环境开启 保证效率
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100);//ms 设置sql执行的最大时间,超时则不执行
        performanceInterceptor.setFormat(true);//是否开启格式化支持
        return performanceInterceptor;
    }
}

2.新建一个类,配置代码生成器

public class MybatisPlusGenerator {
    public static void main(String[] args) {
        //需要构建一个 代码自动生成器 对象
        AutoGenerator autoGenerator = new AutoGenerator();
        //配置策略
        //1、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");//获取用户的目录
        gc.setOutputDir(projectPath+"/src/main/java/")//输出路径
                .setAuthor("choi")//作者名
                .setOpen(false)//是否打开资源管理器
                .setFileOverride(false)//是否覆盖
                .setServiceName("%sService")//去Service的I前缀
                .setIdType(IdType.ID_WORKER)
                .setDateType(DateType.ONLY_DATE)
                .setSwagger2(true);
        autoGenerator.setGlobalConfig(gc);

        //2、配置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUsername("root")
                .setPassword("123456")
                .setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8")
                .setDriverName("com.mysql.cj.jdbc.Driver")
                .setDbType(DbType.MYSQL);
        autoGenerator.setDataSource(dsc);
        //3、包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("test")//模块名
                .setParent("com.choi")//放在哪个包下
                .setEntity("entity")//实体类
                .setMapper("mapper")//mapper
                .setService("service")//service层
                .setController("controller");//controller层
        autoGenerator.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");//逻辑删除
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);//localhost:8080/hello_id_2
        //自动填充设置
        TableFill gmt_creat = new TableFill("gmt_creat", FieldFill.INSERT);
        TableFill gmt_modified = new TableFill("gmt_modified",FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(gmt_creat);
        tableFills.add(gmt_modified);
        strategy.setTableFillList(tableFills);//注意传入的是一个list
        //乐观锁
        strategy.setVersionFieldName("version");

        autoGenerator.setStrategy(strategy);



        autoGenerator.execute();//执行
    }

3.执行后我们可以看到
在这里插入图片描述
可以发现代码都已经生成好了,具体要生成哪个表,怎么生成 改参数即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别卷了球球了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值