MyBatisPlus学习

总结源自:B站遇见狂神说 MyBatisPlus教程地址

Mybatis—plus特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求,BaseMapper
  • 支持 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://baomidou.com/guide/quick-start.html

导入数据库脚本:
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工程

创建一个空的 Spring Boot 工程

可以使用 Spring Initializer (opens new window)快速初始化一个 Spring Boot 工程

添加依赖
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>undefined</version>
    <relativePath/>
</parent>
创建pojo、mapper(不需要mapper.xml文件)
User@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

@Mapper
public interface UserMapper extends BaseMapper<User> {
    //只需要继承BaseMapper<T> 就可以使用BaseMapper中CRUD方法
}
测试
@SpringBootTest
class MybatisplusdemoApplicationTests {

    @Autowired
    private UserMapper userMapper;
    @Test
    void contextLoads() {
        List<User> userList = userMapper.selectList(null);
        userList.forEach(System.out::println);
    }
}
输出结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zCZ6aHx4-1628931210293)(MyBatis—plus.assets/image-20210807162248764.png)]

测试Insert
@Test
public void testInsert() {
    User user = new User();
    user.setAge(4);
    user.setName("zyh");
    user.setEmail("1111111@qq.com");
    int insert = userMapper.insert(user);
    System.out.println(insert);
}
结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E4ofAEEN-1628931210296)(MyBatis—plus.assets/image-20210807162845523.png)]

思考:没有设置id,为什么会插入id呢?

主键生成策略:雪花算法

开源的分布式ID生成ID算法,类型为Long

核心思想:snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是∶使用41bit作为毫秒数,10bit作为机器的ID (5个bit是数据中心,9个bit的机器ID ),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID),最后还有一个符号位,永远是0。

主键自增:
@TableId(type = IdType.AUTO)//主键自增,需要数据库同步设置自增
private Long id;

//其他属性
public enum IdType {
    AUTO(0),//自增
    NONE(1),//未设置主键
    INPUT(2),//手动输入
    ID_WORKER(3),//默认全局Id
    UUID(4),//全局唯一ID
    ID_WORKER_STR(5);//截取字符串表示
}
测试update
@Test
public void testUpdate() {
    User user = new User();
    user.setName("test");
    user.setAge(18);
    user.setId(5L);
    userMapper.updateById(user);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7azc10GH-1628931210298)(MyBatis—plus.assets/image-20210807165415631.png)]

会自动帮我们完成Sql拼接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R5O88kM7-1628931210300)(MyBatis—plus.assets/image-20210807165620882.png)]

自动填充

方式一:数据库级别:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ld4BIgg7-1628931210303)(MyBatis—plus.assets/image-20210807165946535.png)]

再次insert测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CRd470xF-1628931210304)(MyBatis—plus.assets/image-20210807170452623.png)]

发现会自动帮我们创建时间并更新时间

方式二:代码级别

1、删除数据库中属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TEKpq0AN-1628931210305)(MyBatis—plus.assets/image-20210807171918298.png)]

2、在实体类中的属性加注解

@TableField(fill = FieldFill.INSERT)//插入时填充属性
private Date createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)//插入更新时填充属性
private Date updateTime;

3、编写处理器处理注解

@Component
@Slf4j
public class AutoFillHandler implements MetaObjectHandler {

    //插入时的处理策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("开始填充属性");
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

    //更新时的处理策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("开始填充属性");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}
乐观锁

乐观锁:总是认为所有操作不会出现问题,无论什么操作都不会加锁!如果出现了问题,就去更新值测试

悲观锁:总是认为所有操作都会出问题,无论什么操作都会加锁!再去操作!

乐观锁插件

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

1、给数据库加上version字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9zykG0Av-1628931210305)(MyBatis—plus.assets/image-20210807175437388.png)]

2、实体类添加属性,加上@Version注解

@Version//Mybatis_plus乐观锁注解
private Integer verison;

3、注册乐观锁拦截器插件

@Configuration
@MapperScan("com.zyh.mybatisplusdemo.mapper")
@EnableTransactionManagement//自动开始事务管理
public class MyBatisPlusConfig {

    /**
     * 注册乐观锁插件
     * @return OptimisticLockerInterceptor
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

4、测试

乐观锁成功

@Test
public void testOptimisticLocker() {
    //1、查询用户信息
    User user = userMapper.selectById(1L);
    //2、修改用户先息
    user.setName("testOptimisticLock");
    user.setEmail("testOptimisticLock@qq.com");
    //3、更新用户信息
    userMapper.updateById(user);
}

乐观锁失败

@Test
public void testOptimiticLockerFail() {
    //模拟线程1修改属性
    User user1 = userMapper.selectById(1L);
    user1.setName("testOptimisticLock111");
    user1.setEmail("testOptimisticLock@qq11.com");

    //模拟线程2修改属性
    User user2 = userMapper.selectById(1L);
    user2.setName("testOptimisticLock222");
    user2.setEmail("testOptimisticLock@qq22.com");
    userMapper.updateById(user1);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e1ZYpYRM-1628931210306)(MyBatis—plus.assets/image-20210807183509696.png)]

查询操作

selectById:单个查询
@Test
public void testSelectById() {
    //        User user = new User();
    //        user.setEmail("test@test.com");
    //        user.setName("testSelectById");
    //        user.setAge(2);
    User user1 = userMapper.selectById(3L);
    System.out.println(user1);
}
selectByBatchIds:批量查询
public void testSelectByBatchIds() {
    List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    userList.forEach(System.out::println);
}
条件查询map:selectByMap
@Test
public void testSelectByMap() {
    HashMap<String, Object> map = new HashMap<>();
    //自定义查询
    //key是数据库对应字段,value是数据库字段的值
    //Mybatis_plus会去数据库匹配符合map中所有条件的数据并返回一个List
    map.put("name","Tom");
    map.put("id",3L);

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

执行的sql及结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a6SDl9o7-1628931210307)(MyBatis—plus.assets/image-20210807194004190.png)]

分页查询

1、在MyBatisPlusConfig中加入分页插件

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

2、使用Page对象即可

@Test
public void testPageSelect() {
    //Page<当前页,页面大小>
    Page<User> page = new Page<>(1,6);
    userMapper.selectPage(page,null);
    //拿到当前页的记录
    page.getRecords().forEach(System.out::println);
}

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uRPvv53A-1628931210307)(MyBatis—plus.assets/image-20210807200356976.png)]

删除操作

根据id删除数据
// 根据id删除数据@Testpublic void testDeleteById() {    userMapper.deleteById(1423923643572228098L);}
根据ids列表删除
//根据ids删除@Testpublic void  testDeleteByIds() {    userMapper.deleteBatchIds(Arrays.asList(1423923972787326978L,1423923972787326979L,                                            1423923972787326980L));    

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rb2WeZre-1628931210311)(MyBatis—plus.assets/image-20210807201322187.png)]

根据map条件查询
//根据map条件查询@Testpublic void testDeleteMap() {    HashMap<String, Object> map = new HashMap<>();    map.put("name","test");    map.put("age",23);    userMapper.deleteByMap(map);}

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KFuFkAQv-1628931210312)(MyBatis—plus.assets/image-20210807201727641.png)]

逻辑删除

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

逻辑删除:在数据库中没有移除,而是通过一个变量使数据失效,类似于回收站的功能!

测试:
在数据库中加入deleted字段,在实体类加入属性
@TableLogicprivate Integer deleted;
在配置类中加入逻辑删除插件
/*** 逻辑删除插件*/@Beanpublic ISqlInjector sqlInjector() {    return new LogicSqlInjector();}
yml中加入配置
mybatis-plus:  configuration:    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #配置日志  global-config:    db-config:      logic-delete-value: 1      logic-not-delete-value: 0
测试删除
//逻辑删除@Testpublic void logicDelete() {    userMapper.deleteById(1L);}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1tQfmIyd-1628931210313)(MyBatis—plus.assets/image-20210808231214843.png)]

执行后可以看到并没有直接删除,而是将数据库中deleted字段值更改为1,执行的是update操作

再来测试一下select操作,看看数据是否还能被正常查询到
@Testpublic void testLogic() {    User user = userMapper.selectById(1L);    System.out.println(user);}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IhiHXD7G-1628931210314)(MyBatis—plus.assets/image-20210808231642215.png)]

查询不到这个用户,逻辑删除插件会帮我们过滤deleted字段值为1的数据,但是在数据库中这个数据仍然存在。

性能分析插件

在平时开发中,会遇到一些慢查询,MP提供了性能分析插件

1、导入插件

//sql性能分析工具@Bean@Profile({"dev", "test"})public PerformanceInterceptor performanceInterceptor() {    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();    //sql执行最大时间    performanceInterceptor.setMaxTime(100);    performanceInterceptor.setFormat(true);    return performanceInterceptor;}

2、在配置yml

spring:  profiles:    active: dev

条件构造器Wrapper

使用wrapper可以替代一些复杂的sql,使用wrapper中的方法来加入条件执行sql

测试1:查询name不为空、email不为空,年龄大于12的用户信息

@Testpublic void testWrapper() {    QueryWrapper<User> wrapper = new QueryWrapper<>();    wrapper.isNotNull("name")        .isNotNull("email")        .ge("age", 12);//g:大于 e:equals    userMapper.selectList(wrapper).forEach(System.out::println);}

测试2:查询单个数据使用selectOne,多个数据可以使用map或list

@Testpublic void test1Wrapper() {    QueryWrapper<User> wrapper = new QueryWrapper<>();    wrapper.eq("name","Tom");    System.out.println(userMapper.selectOne(wrapper));}

测试3:Between and ,年龄在20-30之间

@Testpublic void test1Wrapper() {    QueryWrapper<User> wrapper = new QueryWrapper<>();    wrapper.between("age",20,30);    Integer count = userMapper.selectCount(wrapper);//查询的区间结果数    System.out.println(count);}

测试4:模糊查询

//模糊查询,名字中不包含y的@Testpublic void test2Wrapper() {    QueryWrapper<User> wrapper = new QueryWrapper<>();    wrapper.notLike("name","y");    List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);    maps.forEach(System.out::println);}

测试5:内查询

//内查询@Testpublic void test3Wrapper() {    QueryWrapper<User> wrapper = new QueryWrapper<>();    wrapper.inSql("id","select id from user where id > 1");    userMapper.selectList(wrapper).forEach(System.out::println);}

测试6:降序升序

@Testpublic void test6() {    QueryWrapper<User> wrapper = new QueryWrapper<>();    wrapper.orderByAsc("id");    userMapper.selectObjs(wrapper).forEach(System.out::println);}

代码自动生成器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值