【MyBatisPlus】【狂神说】学习笔记

MyBatisPlus概述

MyBatis-Plus官网

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

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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.创建数据库
2.创建user表

DROP TABLE IF EXISTS user;

CREATE TABLE user(
	id BIGINT(20) NOT NULL DEFAULT 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)
);

-- 真实开发中,必要的字段:
version(用于乐观锁)
delated(删除逻辑)
gmt_create
gmt_modified

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

3.编写项目,新建一个springboot
4.导入依赖

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

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

说明:我们使用mybatis-plus可以节省我们大量的代码,尽量不要同时导入mybatis-plus和mybatis,会有版本差异

5.连接数据库,这一步和mybatis相同

# mysql 5 驱动不同 com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# mysql 8 驱动不同,需要增加时区的配置 com.mysql.cj.jdbc.Driver 需要增加时区的配置 serverTimezone=GMT%2B8

6.传统方式 pojo-dao(连接没有把提升,配置mapper.xml文件)-service-controller
6.使用了mybatis-plus之后
pojo

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    private Long id;
    private String name;
    private Integer age;
    private String email;

}

mapper接口

@Mapper
// 在对应的mapper上面继承基本的类BaseMapper
public interface UserMapper extends BaseMapper<User> {
    // 所有的CRUD已经编写完成
    // 不需要像以前一样配置一大堆文件


}

注意:我们需要在主启动类上去扫描我们mapper包下的所有的接口


@MapperScan("com.hupf.mptest.mapper")
@SpringBootApplication
public class MptestApplication {

    public static void main(String[] args) {
        SpringApplication.run(MptestApplication.class, args);
    }

}

测试类

@SpringBootTest
class MptestApplicationTests {


    // 继承了BaseMapper,所有的方法都来自父类
    // 我们也可以编写自己的扩展方法
    @Autowired
    private UserMapper usermapper;

    @Test
    void contextLoads() {
        // 参数是一个mapper,条件构造器,我们先不写条件,直接传null
        // 查询所有的数据
        List<User> users = usermapper.selectList(null);
        users.forEach(System.out::print);
    }

}

思考:
1.SQL谁帮我们写的?mybatis-plus
2.方法哪里来的?mybatis-plus

配置日志

我们所有的sql现在是不可见的,我们希望知道他是怎么执行的,所以我们必须要看日志

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

配置完毕日志之后,后面的学习就需要注意这个自动生成的SQL,我们就会喜欢上myBatis_plus

CRUD扩展

插入数据

@Test
    void testInsert() {
        User user = new User();
        user.setName("JAVA");
        user.setAge(19);
        user.setEmail("xxxxx@qq.com");

        // 自动生成ID
        int insert = usermapper.insert(user);
        // 输出受影响的行数
        System.out.println(insert);
        // 发现,ID会自动回填
        System.out.println(user);
    }

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

主键生成策略

分布式唯一ID生成方法有很多

雪花算法

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

给大家举个例子吧,比如下面那个 64 bit 的 long 型数字:

第一个部分,是 1 个 bit:0,这个是无意义的。

第二个部分是 41 个 bit:表示的是时间戳。

第三个部分是 5 个 bit:表示的是机房 id,10001。

第四个部分是 5 个 bit:表示的是机器 id,1 1001。

第五个部分是 12 个 bit:表示的序号,就是某个机房某台机器上这一毫秒内同时生成的 id 的序号,0000 00000000。

主键自增

需要配置主键自增:
1.实体类字段上

@TableId(type=IdType.AUTO)

2.数据库字段一定要是自增
3.测试插入数据即可

ID策略:

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

更新操作

@Test
    void testUpdate() {
        User user = new User();
        user.setId(100L);
        user.setName("JAVA");
        user.setAge(19);
        user.setEmail("xxxxx@qq.com");

        int insert = usermapper.updateById(user);
        System.out.println(insert);
        System.out.println(user);
    }

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

自动填充

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

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

方式一:数据库级别(不建议在工作中修改数据库)
1.在表中新增gmt_create,gmt_modified字段
2.先同步实体类,再次测试插入方法啊

方式二:代码级别
1.删除数据库中的默认值,更新操作
2.实体类的字段上需要增加注解了

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

@TableField(fill=FieldFill.INSERT_UPDATE)
private Date gmt_modified;

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

@Slf4j
@Component// 一定不要忘记将处理器加入到IOC
public class MyMeteHandler implements MetaObjectHandler {

    // 插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("开始插入");
        this.setFieldValByName("gmt_create",new Date(),metaObject);


    }

    // 更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("开始更新");
        this.setFieldValByName("gmt_modified",new Date(),metaObject);


    }
}

4.测试更新,观察时间

乐观锁

在面试过程中,我们经常会被问道乐观锁,悲观锁

乐观锁:十分乐观,总是认为不会出现问题,无论做什么都不会加锁,如果出现问题,再次更新测试

悲观锁:十分悲观,总是认为总是会出现问题,无论做什么都会上锁,再去操作

乐观锁实现方式:
1.取出记录时,获取当前version
2.更新时,带上这个version
3.执行更新时,set version = newVerison where version=oldVersion
4.如果version不对,就更新失败

乐观锁实现方式例子

1.取出记录时,获取当前version
2.更新时,带上这个version
update user set name = "kuangshen",version=version+1
where id=2 and version=1;

是同过判断verison是否等于之前的version的值的方式来判断是否可以更新,同时也可以避免多线程问题

测试乐观锁插件

1.给数据库中增加version字段
2.实体类加对应的字段

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

3.注册组件

// 扫描我们的mapper文件夹
@MapperScan("com.hupf.mptest.mapper")
@EnableTransactionManagement
@Configuration// 配置类
public class MyBatisPlusConfig {

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


}

4.测试一下

// 测试乐观锁成功
    @Test
    void testOptimisticLocker() {
        // 查询用户
        User user = usermapper.selectById(1L);
        // 修改客户
        user.setName("JAVA");
        user.setEmail("xxxxx@qq.com");
        // 执行更新操作
        usermapper.updateById(user);
    }

    // 测试乐观锁失败
    @Test
    void testOptimisticLocker2() {
        // 线程1
        User user = usermapper.selectById(1L);
        user.setName("BBB");
        user.setEmail("xxxxx@qq.com");

        // 线程2  抢先更新
        User user2 = usermapper.selectById(1L);
        user2.setName("AAA");
        user2.setEmail("xxxxx@qq.com");
        usermapper.updateById(user2);

        
        usermapper.updateById(user);
    }

查询

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

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

    // 条件查询 map
    @Test
    public void testSelectByBatchIds(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","hupf");

        List<User> users = usermapper.selectByMap(map);
        users.forEach(System.out::print);
    }

分页查询

配置拦截器组件即可

// 扫描我们的mapper文件夹
@MapperScan("com.hupf.mptest.mapper")
@EnableTransactionManagement
@Configuration// 配置类
public class MyBatisPlusConfig {

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


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

}

测试分页查询

	// 测试分页查询
    @Test
    public void testPage(){
        // 参数一:当前页
        // 参数而:页面条数
        Page<Object> page = new Page<>(1,5);
        usermapper.selectPage(page, null);
        page.getRecords().forEach(System.out::print);
    }

删除操作

根据ID删除记录

	// 测试删除
    @Test
    public void testDeleteById(){
        usermapper.deleteById(1L);
    }

    // 批量删除
    @Test
    public void testDeleteBatchId(){
        int i = usermapper.deleteBatchIds(Arrays.asList(12, 3, 5));
    }

	// 通过map删除
    @Test
    public void testDeleteMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","hupf");

        usermapper.deleteByMap(map);
    }

逻辑删除

物理删除:从数据库中直接删除
逻辑删除:在数据库中没有被移除,而是通过一个变量让他失效

类似回收站

测试一下:
1.在数据库中增加deleted字段
2.实体类中增加属性

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

3.配置到IOC容器

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

application.properties文件中添加

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

真实数据依然存在数据库,只是deleted被设置为1
并且在查询的时候,mybatis-plus回自动动态修改sql语句,加上where deleted = 0的

性能分析插件

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

我们在平时的开发中,会遇到一些慢sql
MP提供了性能分析插件,如果超过这个时间就停止运行
1.导入插件

// SQL性能分析拦截器
@Bean
// 设置dev test环境开启,保证我们的效率
@Profile({"dev","test"})
public ISqlInjector sqlInjector(){
    PerformanceInterceptor p = new PerformanceInterceptor();
	p.setMaxTime(100);// 毫秒, 设置sql执行的最大时间,如果超过了就不执行
	p.setFormat(true);// sql输出格式化
	return performanceInterceptor ;
}

要在springboot中设置环境为开发环境

2.测试插件

@Test
void contextLoads(){
	// 参数是一个wrapper,条件构造器,这里用null
	List<User> users = userMapper.selectList(null);
	users.forEach(System.out::println);
}

使用性能分析插件,可以帮助我们提高效率

条件构造器

十分重要 :warpper
可以代替复杂sql语句

@SpringBootTest
class MptestApplicationTests {
    @Autowired
    private UserMapper usermapper;

    @Test
    void contextLoads() {
        // 查询name不为空,并且邮箱不为空,并且奈年龄大于等于12
        QueryWarpper<User> warpper = new QueryWarpper();
        warpper.isNotNull("name").isNotNull("email").ge("age",12);
       	userMapper.selectList(warpper).forEach(System.out::println); 
    }

	@Test
    void contextLoads2() {
        // 查询name是狂神说
        QueryWarpper<User> warpper = new QueryWarpper();
        warpper.eq("name","狂神说");
       	userMapper.selectList(warpper).forEach(System.out::println); 
    }

	@Test
    void contextLoads3() {
        QueryWarpper<User> warpper = new QueryWarpper();
        // 查询年龄在20到30之间的用户
        warpper.between("age",20,30);
        // 字段不包含e的
        warpper.notLike("name","e");
        // 左右 %e%
        warpper.likeRight("name", "h");
        // 字段不包含e的
        warpper.notLike("name","e");
        // id在子查询中查出来
        warpper.inSql("id","select id from user where id<3");
    }

}

代码自动生成器

dao,pojo,service,controller都可以自动生成

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

// 代码自动生成器
public class AutoCode{
	@Test
	public void makeAutoCode(){
		// 需要构建一个代码生成器对象
		AutoGenerator mpg = new AutoGenerator();
		// 配置策略
		// 全局配置
		ClobalConfig gc= new ClobalConfig();
		String projectPath = System.getProperty("user.dir");
		gc.setOutputDir(projectPath+"/src/main/java");
		gc.setAuthor("作者");
		gc.setOpen(false);
		gc.setFileOverrride(false);// 是否覆盖
		gc.setServiceName("%sService");//去除serivce的I前缀
		gc.setIdType(IdType.ID_WORKER);
		gc.setDateType(DateType.ONLY_DATE);
		gc.setSwagger2(true);
		mpg.setGlobalConfig(gc);

		// 设置数据源
		DataSourceConfig dsc = new DataSourceConfig();
		dsc.setUrl("jdbc....");
		dsc.setDriverName("com.mysql.cj.jdbc.Driver");
		dsc.setUsername("root");
		dsc.setPassword("123456");
		dsc.setDbType(DbType.MYSQL);
		mpg.setDataSource(dsc);

		// 包的配置
		PackageConfig pc = new PackageConfig();
		pc.setModuleName("blog");
		pc.setParent("com.hupf");
		pc.setEntity("pojo");
		pc.setMapper("mapper");
		pc.setService("service");
		pc.setController("controller");
		mpg.setPackageInfo();		

		// 策略配置
		StrategyConfig strategy = new StrategyConfig();
		
		// 设置要映射的表名
		strategy.setInclude("user");
		strategy.setNaming(NamingStrategy.underline_to_camel);
		strategy.setColumnNaming(NamingStrategy.underline_to_camel);
		strategy.setSuperEntityClass("父类,没有则不需要设置");
		strategy.setEntityLombokModel(true);
		strategy.setRestControllerStyle(true);
		strategy.setLogicDeleteFieldName("deleted");
		
		// 自动填充配置
		TableFill gmtcreate = new TableFill("gmt_create",FieldFill.INSERT);
		TableFill gmtmodified = new TableFill("gmt_modifiied",FieldFill.INSERT_UPDATE);
		ArrayList<TableFill> tableFills = new ArrayList<>();
		tableFills.add(gmtcreate);
		tableFills.add(gmtmodified);
		strategy.setTableFillList(tableFills);

		// 乐观锁
		strategy.setVersionFieldName("verison");
		strategy.setControllerMappingHyphenStylr(true);
		

		mpg.setStrategy(strategy);
		mpg.execute();

	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值