Mybatisplus

Mybatisplus

为什么要用Mybatisplus?

MybatisPlus可以节省我们大量的工作时间所有的CRUD代码都可以自动化完成

JPA、tk-mapper、Mybatisplus

简介

是什么?Mybatis本来就是简化JDBC操作的

官网:https://mp.baomidou.com/ MybatisPlus,简化Mybatis

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NKy2hJUB-1610587006699)(/Users/404notfound/Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/Users/342644552/QQ/Temp.db/AE0038E2-CF4C-4409-BE4E-E5BF07B3BEE8.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gUbbLxLn-1610587006700)(/Users/404notfound/Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/Users/342644552/QQ/Temp.db/24C67610-22E0-4498-AAEB-06234575290A.png)]

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作,baseMapper
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求,简单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 操作智能分析阻断,也可自定义拦截规则,预防误操作

快速入门

地址:https://mp.baomidou.com/guide/quick-start.html#%E5%88%9D%E5%A7%8B%E5%8C%96%E5%B7%A5%E7%A8%8B

使用第三方组件:

1、导入对应的依赖

2、研究依赖如何配置

3、代码如何编写

4、提高拓展技术能力

步骤

1、创建数据库 mybatis_plus

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

2、创建User表

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

--真实开发中,version(乐观锁)、deleted(逻辑删除)、create(创建)、modified(修改)

3、编写项目、使用SpringBoot初始化

1、导入依赖

<parent>
  <groupId> org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.5.RELEASE</version>
</parent>

<dependencies>
  <!--lombok-->
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  </dependency>

  <!--mysql驱动-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
  </dependency>

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

  <!--web-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
  </dependency>

  <!--test-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
  </dependency>
</dependencies>

说明:我们使用Mybatisplus可以节省大量的代码,尽量不要同时导入mybatisplus、mybatis依赖,版本差异

5、连接数据库,和mybatis相同

# mysql 5   驱动不同    com.mysql.jdbc.Driver
# mysql 8   驱动不同、需要增加时区的配置  com.mysql.cj.jdbc.Driver    serverTimezone=GMT%2B8
spring.datasource.data-username=root
spring.datasource.data-password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=ture&characterEncoding=utf-8

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

6、使用了Mybatis-puls之后

  • pojo

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

    /**
     * 在对应的mapper上实现基本的接口 BaseMapper
     */
    @Component//代表持久层
    public interface UserMapper extends BaseMapper<User> {
        //所有的CRUD操作已经编写完成
        //不需要像以前一样配置一大堆文件
    }
    
  • 注意点:我们需要在主启动类上去扫描我们的mapper包下面的所有接口@MapperScan("cn.sx.mapper")

  • 测试类中写测试

    @SpringBootTest
    @RunWith(SpringRunner.class)
    public class UserMapperTest{
    
        /**继承了BaseMapper,所有的方法都来自父类*/
        @Autowired
        private UserMapper userMapper;
    
        @Test
        public void testLoads() {
            //查询全部用户
            List<User> users = userMapper.selectList(null);
            users.forEach(System.out::println);
        }
    }
    

在这里插入图片描述

思考

1、SQL谁写的?Mybatis_Plus都写好了

2、方法哪儿来的?Mybatis_Plus都写好了

配置日志

我们所有的sql现在是不可见的,如果希望知道他是怎么执行的,需要在日志里查看

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

在这里插入图片描述

CRUD拓展

插入操作

Insert 插入

//测试插入
    @Test
    public void testInsert() {

        User user = new User();
        user.setName("kuangshen");
        user.setEmail("342644552@qq.com");
        user.setAge(27);

        //查询全部用户
        int result = userMapper.insert(user);   //会帮我们自动生成id
        System.out.println(result); //受影响的行

        System.out.println(user);   //id自动回填
    }

在这里插入图片描述

数据库插入的id为默认值为:全局的唯一id

主键生成策略

默认 ID_WORKER(全局唯一ID)

分布式id唯一生成策略:https://www.cnblogs.com/yizhou35/p/12031366.html

雪花算法SnowFlake:

SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用41bit作为毫秒数,10bit作为机器的ID( 5个bit是数据中心,5个bit是机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以生成2096个ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一!

主键自增

我们需要配置主键自增:

1、实体类字段上@TableId(type = IdType.AUTO)

2、数据库字段一定要是自增

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tla0FzS0-1610587006705)(/Users/404notfound/Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/Users/342644552/QQ/Temp.db/18BFC82D-0CD2-4A85-8121-1F5E67E1D3BF.png)]

3、再次测试插入即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s3l47TAF-1610587006705)(/Users/404notfound/Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/Users/342644552/QQ/Temp.db/F00B34FA-FF16-48FA-BEAD-F2D1392FD028.png)]

其他源码解释

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

更新操作

//测试更新
@Test
public void testUpdate() {
	//通过条件自动拼接动态sql
  User user = new User();
  user.setId(1L);
  user.setName("kuangshen333");
  user.setEmail("22222@qq.com");
  user.setAge(12);

  // 注意:updateById 但是参数是一个 对象!
  int result = userMapper.updateById(user);
  System.out.println(result);

  System.out.println(user);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ixrFWlnQ-1610587006706)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113143622200.png)]

所有sql都是自动动态配置的

自动填充

创建时间、修改时间!这些操作一般都是自动化完成的,我们不希望手动更新!

阿里巴巴开发手册:所有数据库表:gmt_create、gmt_modified 几乎所有的表都要自动配置上,而且需要自动化

方式一:数据库级别 (工作中不允许修改数据库)

1、在表中新增字段create_time 、update_time

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jmzw9Euk-1610587006707)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113144415421.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NXnlBEMs-1610587006707)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113144427998.png)]

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

private Date createTime;
private Date updateTime;

3、再次更新查看结果即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ARahner-1610587006708)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113144810439.png)]

方式二:代码级别

1、删除数据库中的默认值、更新操作

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

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

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

3、编写处理器来处理这个注解即可

@Slf4j
@Component  //要交给IOC容器中
public class MyMetaObjectHandler implements MetaObjectHandler {

    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill......");
        /*
         *  String fieldName
         *  Object fieldVal
         *  MetaObject metaObject
         */
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

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

//自动填充暂时不用

乐观锁

在面试过程中,经常被问到乐观锁,悲观锁

乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无关干什么都不回去上锁,如果出现问题再次更新值测试

悲观锁:顾名思义十分悲观,它总是认为总是出现问题,无论干什么都会上锁,再去操作

version、new version

乐观锁实现方式:

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

--B线程抢先完成(模拟),version = 2,会导致 A 修改失败
update user set name = "Mass", version = version + 1
where id = 2 and version = 1

测试MyBatis乐观锁插件

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nmsaDA6U-1610587006709)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113162116567.png)]

2、实体类加上相应的version字段

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

3、注册组件

@Configuration  //配置类
@EnableTransactionManagement  //事务
@MapperScan("cn.sx.mapper")  //扫描mapper文件夹
public class MybatisplusConfig {

  //注册乐观锁插件
  @Bean
  public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor(){
    return new OptimisticLockerInnerInterceptor();
  }
}

最新版弃用

4、测试乐观锁

//测试乐观锁成功
@Test
public void testOptimisticLocker() {
  User user = userMapper.selectById(1349160234182021135L);
  user.setAge(100);
  user.setName("222@qq");
  userMapper.updateById(user);
}

//测试乐观锁失败(模拟多线程下)
@Test
public void testOptimisticLocker2() {
  User user = userMapper.selectById(1L);
  user.setAge(100);
  user.setName("222@qq");

  //模拟另外一个线程插队操作
  User user2 = userMapper.selectById(1L);
  user2.setAge(1000);
  user2.setName("666@qq");

  userMapper.updateById(user);    //如果没有乐观锁就会覆盖插队线程的值
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NEdrVadi-1610587006709)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113164751584.png)]
在这里插入图片描述

查询操作

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

//批量查询
@Test
public void testSelectBatchIds() {
  List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
  users.forEach(System.out::println);
}

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

分页查询

分页在网站使用十分之多!

1、原始的 limit 进行分页

2、pageHandler 等第三方插件

3、Mbatis其实也内置了分页插件

如何使用

1、配置拦截器组件

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

2、直接使用Page对象

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

删除操作

//测试删除
@Test
public void testDeleteById() {
  int i = userMapper.deleteById(1349160234182021135L);
  System.out.println(i);  //被操作的行
}

//测试批量删除
@Test
public void testDeleteBatchId() {
  userMapper.deleteBatchIds(Arrays.asList(5,6,7));
}

//测试通过条件
@Test
public void testDeleteMap() {
  HashMap<String, Object> map = new HashMap<>();
  map.put("name","Sandy");
  userMapper.deleteByMap(map);
}

我们在工作中会遇到的一些问题:逻辑删除

逻辑删除

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

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

管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!

测试一下:

1、在数据库中增加一个deleted字段 默认值为0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AbjGJC11-1610587006710)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113171509636.png)]

2、在实体类中增加属性 deleted

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

3、配置

//逻辑删除组件
public ISqlInjector iSqlInjector(){
  return new LogicSqlInjector();
}
最新版弃用
#配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-field=flag
mybatis-plus.global-config.db-config.logic-not-delete-value=0
mybatis-plus.global-config.db-config.logic-delete-value=1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-maXd2l0z-1610587006711)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113172634533.png)]
记录依旧在数据库,但是deleted值已经变了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fm81bwix-1610587006712)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113172746803.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HBgRpb1C-1610587006713)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113172909753.png)]

性能分析插件

作用:性能分析拦截器,用于输出每条sql语句及其执行时间

我们在平时的开发中会遇到一些慢sql,测试、druid。。。

MybatisPlus也提供性能分析插件,如果超过这个时间就停止运行

1、导入插件

#设置开发环境
spring.profiles.active=dev
//sql执行效率插件
@Profile({"dev","test"})  //设置 dev test 环境开启 保证我们的效率
@Bean
public PerformanceInterceptor performanceInterceptor() {
  PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
  //工作中常用,不允许用户等待
  performanceInterceptor.setMaxTime(100);   //ms 设置sql执行的最大时间(微妙),如果超过了就不执行
  performanceInterceptor.setFormat(true); //sql 格式化
  return performanceInterceptor;
}

2、测试使用

@Test
public void testLoads() {
  //查询全部用户
  List<User> users = userMapper.selectList(null);
  users.forEach(System.out::println);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bJa1xrjU-1610587006713)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113174836507.png)]

条件构造器

十分重要:Wrapper

我们写一些复杂的sql就可以使用它来代替

1、测试一

@Test
public void testLods() {
  // 查询name、邮箱不为空,年龄大于等于12岁的
  QueryWrapper<User> wrapper = new QueryWrapper<>();
  wrapper.isNotNull("name")
    .isNotNull("email")
    .ge("age",12);
  List<User> users = userMapper.selectList(wrapper);//和刚刚的map对比一些
  users.forEach(System.out::println);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4crQQQ3v-1610587006714)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113152730407.png)]

2、测试二

@Test
public void test2() {
  // 查询name为  kuangshen333
  QueryWrapper<User> wrapper = new QueryWrapper<>();
  wrapper.eq("name","kuangshen333");
  User user = userMapper.selectOne(wrapper);  //查询一个数据
  System.out.println(user);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xrudOy3p-1610587006714)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113153039740.png)]

3、测试三

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VxvPRz6I-1610587006715)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113153428258.png)]

4、测试四

//模糊查询
@Test
public void test4() {
  // 查询age 在20 ~ 30 之间的用户
  QueryWrapper<User> wrapper = new QueryWrapper<>();
  wrapper.notLike("name", "99")
    .likeRight("email", "t")    //likeRight 左%
    .likeLeft("email","m");     //likeLeft 右%
  List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
  maps.forEach(System.out::println);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-em552dmJ-1610587006715)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113154104178.png)]

5、测试五

@Test
public 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);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4pWWd5RJ-1610587006716)(/Users/404notfound/Library/Application Support/typora-user-images/image-20210113154516769.png)]

6、测试六

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

在这里插入图片描述

代码自动生成器

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

官网地址:https://mp.baomidou.com/guide/generator.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值