mybatis-plus学习

Mybatis—plus

官网:https://baomidou.com/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CmcCe63t-1613443284747)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210215204507297.png)]

MyBatis-Plus是什么?

MyBatis-Plus 是一个 MyBatis 的增强,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

plus就是“大,升级”的意思

特性

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

快速入门

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

2.创建一个springboot应用

3.导入Mybatis-plus的依赖

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

4.配置数据源

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eCQf5i3o-1613443284751)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210215205615054.png)]

mysql 5
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql:///mybatisplus?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
mysql 8  url中还要配置时区
	url: jdbc:mysql:///mybatisplus?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC

5.pojo、Controller、mapper

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



@RestController
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @RequestMapping("queryAllUser")
    public String queryAllUser(){
        List<User> users = userMapper.selectList(null);
        String res = JSON.toJSONString(users);
        return res;
    }
}



@Repository
public interface UserMapper extends BaseMapper<User> {
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0CMAUziL-1613443284754)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210215212510274.png)]

可以看到,我们再UserMapper中没有写任何东西,但是却可以调用UserMapper的方法,这是为什么呢?

所有的答案都来自于这儿:继承了BaseMapper接口+泛型

点进BaseMapper中去看看:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p6QVNlEk-1613443284757)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210215213100756.png)]

配置日志

方法:

#配置日志 直接在控制台输出
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tpw7WKKB-1613443284759)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210215213633895.png)]

CRUD

插入

@PostMapping("insert")
    public String insert(@RequestBody User user){
        System.out.println("user1:"+user);
        int result = userMapper.insert(user);
        System.out.println("result:"+result);
        return JSON.toJSONString(user);
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uh9TT77d-1613443284760)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210215215512488.png)]

这里我并没有传入id,但是mybatis-plus自动给我生成了一个id,没主键就插不进去,这好理解。

那么这里主键的生成策略是什么呢?是随机的吗?

不是,这里是用雪花算法生成的

SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应用十分广泛,且ID 引入了时间戳,基本上保持自增的,后面的代码中有详细的注解。

如何改变主键的生成策略呢?

public class User {
    
    @TableId(type=IdType.AUTO)
    private Long id;
    
    private String name;
    private int age;
    private String email;
}

其中,IdType取枚举值:

public enum IdType {
    AUTO(0),	//自增
    NONE(1),	//没有主键
    INPUT(2),	//手动输入
    ASSIGN_ID(3),//雪花算法生成id
    ASSIGN_UUID(4),//uuid

更新

 @PutMapping("update")
    public String update(@RequestBody User user){
        System.out.println("user:"+user);
        //根据id来修改,但是参数是user对象
        int i = userMapper.updateById(user);
        System.out.println("i="+i);
        return JSON.toJSONString(user);
    }

可以自动实现条件拼接

自动填充

在开发中,像生成时间、修改时间等与时间相关的属性都是自动填充的,绝对不允许手动输入!

首先,在数据库上添加生成时间、修改时间两个字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6vmNCy9X-1613443284761)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210215225638301.png)]

同步实体类,并且添加注解

public class User {
    @TableId(type=IdType.AUTO)
    private Long id;
    private String name;
    private int age;
    private String email;
    @TableField(fill = FieldFill.INSERT)	//添加时填充
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)//添加和更新时填充
    private LocalDateTime updateTime;
}

编写处理器,别忘了把他加到ioc容器中去 (忘记了可以看官网)

@Component
public class MyHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        System.out.println("start......");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class,LocalDateTime.now());
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

乐观锁

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

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

乐观锁的实现方式:

  • 取出时,读取出version
  • 修改时,set version=newVersion where version=oldVersion

操作步骤:

1.给数据库添加version字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BF457zzk-1613443284762)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210215232340333.png)]

2.同步实体类

@Version    //乐观锁
private Integer version;

3.注册组件

@MapperScan("com.xianyu.mapper")
@EnableTransactionManagement    //事务自动管理
@Configuration
public class MyBatisConfig {

    //注册乐观锁插件
  
    /*该方法已经弃用
    @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 testOptimistic(){
        User user = userMapper.selectById(1L);
        user.setName("lzh咸鱼翻身");
        userMapper.updateById(user);
    }

5.失败测试

 @Test
    public void testOptimistic2(){
        User user = userMapper.selectById(2);
        user.setName("咸鱼fffff");

        User user1 = userMapper.selectById(2);
        user1.setName("咸鱼sssss");

        userMapper.updateById(user1);
        userMapper.updateById(user);
    }
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@38a96593] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@424384387 wrapping com.mysql.cj.jdbc.ConnectionImpl@6f0c45f4] will not be managed by Spring
==>  Preparing: UPDATE user SET name=?, age=?, email=?, update_time=?, version=? WHERE id=? AND version=?
==> Parameters: 咸鱼sssss(String), 20(Integer), test2@baomidou.com(String), 2021-02-15T23:46:07.442079300(LocalDateTime), 2(Integer), 2(Long), 1(Integer)
<==    Updates: 1						//更新了1条
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@38a96593]




Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@543b0737] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1850116381 wrapping com.mysql.cj.jdbc.ConnectionImpl@6f0c45f4] will not be managed by Spring
==>  Preparing: UPDATE user SET name=?, age=?, email=?, update_time=?, version=? WHERE id=? AND version=?
==> Parameters: 咸鱼fffff(String), 20(Integer), test2@baomidou.com(String), 2021-02-15T23:46:07.453050900(LocalDateTime), 2(Integer), 2(Long), 1(Integer)
<==    Updates: 0						//更新了0条

查询

批量查询

 	 @Test
    public void testBranch(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        for (User user : users) {
            System.out.println(user);
        }
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wyu7LYCA-1613443284764)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210215235816231.png)]

条件查询的方法之一 ————map

@Test
    public void testMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "咸鱼");
        List<User> users = userMapper.selectByMap(map);
        for (User user : users) {
            System.out.println(user);
        }
    }

查询出所有name为咸鱼的人

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bwva2hxt-1613443284765)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216000045756.png)]

分页查询

1.原始的limit分页

2.pagehelper分页

3.MP其实也内置了分页插件

  1. 配置组件
 //分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

​ 2.直接使用page对象即可

 @Test
    public void testPage(){
        Page<User> page = new Page<>(1, 5);
        userMapper.selectPage(page, null);
        List<User> records = page.getRecords();
        for (User record : records) {
            System.out.println(record);
        }
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GND2TjZr-1613443284771)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216001306589.png)]

删除

	@Test
    public void testDel(){
        //通过id删除
        userMapper.deleteById(1361312829864538120L);
    }
    @Test
    public void testDel2(){
        //通过id批量删除
        userMapper.deleteBatchIds(Arrays.asList(1,2,3,4));
    }

    @Test
    public void testDelMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("age", 24);
        //通过map删除
        userMapper.deleteByMap(map);
    }

逻辑删除

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

逻辑删除:没有从数据库中删除,而是通过一个变量使其失效 deleted =0 --> deleted=1

1.数据库中增加一个deleted的字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Seaw13Vs-1613443284772)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216002208547.png)]

2.pojo中新增属性

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

3.application.yml中配置值

  global-config:
    db-config:
      logic-delete-value: 1
      logic-not-delete-value: 0

4.测试

@Test
    public void testDel(){
        //通过id删除
        userMapper.deleteById(1361312829864538119L);
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-67dZgiKS-1613443284773)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216003452314.png)]

测试一下查找

@Test
public void testfind(){
    //通过id删除
    userMapper.selectById(1361312829864538119L);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7iw2ryGD-1613443284774)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216003652079.png)]

自动拼接上了逻辑删除

性能分析插件

MP提供了一款性能测试插件来测试慢sql,如果执行时间超过这个时间就停止运行!

分析每条sql执行的时间

3.x版本以上mp弃用了

条件构造器

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

测试一

	@Test
    public void test1(){
        //查询name、email不为空,且年龄大于12的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
                .isNotNull("email")
                .gt("age", 12);
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-39zcfcMg-1613443284775)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216092142475.png)]

测试二

 	@Test
    public void test2(){
        //查询名字等于咸鱼的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name", "咸鱼");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1uHiNrIS-1613443284776)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216092423877.png)]

测试三

@Test
public void test3(){
    //测试查询年龄在20-30之间的用户
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age", 20, 30);
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r2rLKjJ0-1613443284776)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216092728490.png)]

测试四

@Test
public void test4(){
    //测试模糊查询
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.notLike("name", "y")
            .likeRight("id", "13");
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OoIaJhJU-1613443284777)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216093008033.png)]

测试五

@Test
public void test5(){
    //测试子查询
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.inSql("id", "select id from user where id < 1361312829864538115");
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CiSUjGcC-1613443284778)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216093311131.png)]

测试六

 @Test
    public void test6(){
        //测试排序查询
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");  //id逆序排序
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qplzOWoy-1613443284779)(C:\Users\11384\AppData\Roaming\Typora\typora-user-images\image-20210216093537077.png)]

代码自动生成器

package com.kuang;
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("狂神说");
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/kuang_community?
useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.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.kuang");
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("blog_tags","course","links","sys_settings","user_record","
user_say"); // 设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true); // 自动lombok;
strategy.setLogicDeleteFieldName("deleted");
// 自动填充配置
TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified",
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(); //执行
}
}

easycode替代!

上一篇:Mybatis学习笔记整理


下一篇:Mybatis—代理开发和核心配置文件深入