苦行僧DH

博客园 首页 新随笔 联系 订阅 管理

介绍

简介

[MyBatis-Plus](https://github.com/baomidou/mybatis-plus)(简称 MP)是一个 [MyBatis](http://www.mybatis.org/mybatis-3/) 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 
官网是这样说的:
他们愿景成为mybatis的搭档,就像魂斗罗的1p和2p,**好基友搭配,干活不累**。

特征

# 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
# 损耗小:启动即会自动注入基本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操作智能分析阻断,也可自定义拦截规则,预防误操作

支持数据库

	mysql 、mariadb 、oracle 、db2 、h2 、hsql 、sqlite 、postgresql 、sqlserver 、presto 、Gauss 、Firebird
	Phoenix 、clickhouse 、Sybase ASE 、 OceanBase 、达梦数据库 、虚谷数据库 、人大金仓数据库 、南大通用数据库 、

使用

引入依赖

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!--mybatis-plus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--lombok用来简化实体类-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

注意:引入mybatis-plus后不要在引入mybatis,避免版本差异问题

编写实体类

给类名加@TableName,详解:https://baomidou.com/guide/annotation.html#tablename
给id字段写@TableId,详解:https://baomidou.com/guide/annotation.html#tableid
给普通字段写@TableField,详解:https://baomidou.com/guide/annotation.html#tablefield

注意名称与数据库对应。

创建Mapper接口

public interface UserMapper extends BaseMapper<User> {

启动类加注解

@MapperScan("xxx.xxx.xxx.mapper")

加入配置

# 配置SQL日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 配置自动驼峰式编码
mybatis-plus.configuration.map-underscore-to-camel-case: false

启动调用mapper的方法

注意mapper,然后调用mapper的方法即可。
我们会发现我们mapper中没有代码,但是仍然可以使用。

常用CRUD方法

插入Insert

操作

int resultLen = mapper.insert(T);

注意:我们这里没有设置主键生成策略,默认是ID_WORKER(雪花算法)策略,

主键生成策略

# myabtisPlus的id生成策略默认是ID_WORKER全局唯一ID
自增策略其实有很多,比如数据库自增,UUID,自己设计、redis原子操作等。各有各的好处坏处,比如数据库自增不利于分库分表,UUID不利于排序和存储、自己设计容易出bug,难度大(大佬请忽略)、redis生成有限制必须使用redis。
参考资料:分布式系统唯一ID生成方案汇总:https://www.cnblogs.com/haoxinyue/p/5208136.html
# 配置id的自增策略
1、给某张表某个ID字段加:@TableId(type=IdType.xxxxx),具体看文档https://baomidou.com/guide/annotation.html#tableid
2、全局设置:mybatis-plus.global-config.db-config.id-type=auto,具体也是看官网文档

更新Update

操作

int result = mapper.update(T);
注意:
    其SQL生成是动态的,比如说我们更新一个User对象,其中有三个字段id,name,age,然后我们创建一个User对象,然后只setAge(20),setId(1),不设置name,那么mybatisplus生成的SQL就是:update user set age = 20 where id = 1。

自动填充

这个是咋回事呢,比如说我们数据中有creatTime和updateTime,然后我们想在insert的时候让mybatisplus自动帮我们填充creatTime和updateTime,update的时候让mybatisplus帮我们自动更新updateTime,这个就是自动填充。

操作如下:

1、给字段加注解

	@TableField(fill = FieldFill.INSERT) // 代表着插入的时候会填充值
    private Date createTime;
    //@TableField(fill = FieldFill.UPDATE)	// 代表着更新的时候会填充值
    @TableField(fill = FieldFill.INSERT_UPDATE)	// 代表着插入和更新会填充值
    private Date updateTime;

2、写类实现MetaObjectHandler接口

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    /*当insert的时候调用*/
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime", new Date(), metaObject);
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
    
    /*当update的时候调用*/
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}

乐观锁

使用场景:我们更新一条数据之前,希望这条数据没有被别人更新过。

举例:有一名员工的工资salary是3000,这时人事经理想来将这salary改为2000,然后总经理想将salary改为5000,然后他们都填好了想修改的salary,然后人事经理先提交,然后总经理后提交,完了后我们人事经理发现咋钱越改越多呢,这个时候就出现了问题,这个就是丢失更新,解决办法可以这样,我们给加一个version字段,然后每次更改后都将version+1,只有当前version和待修改的version一致,那么才能修改,这个version就可以看成一个乐观锁。我们加了version以后,前面的例子最初version为1,人事经理改完后version为2,这时候总经理那里拿到的还是version为1的数据,它来修改的话,手里的version比数据库中的version低,故而不允许修改。

那么myabtisplus里面就可以实现这个version。

官方解释

# 意图:
	当要更新一条记录的时候,希望这条记录没有被别人更新
# 乐观锁实现方式:
    取出记录时,获取当前version
    更新时,带上这个version
    执行更新时, set version = newVersion where version = oldVersion
    如果version不对,就更新失败

那么如何使用

1、插件配置:

@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    return new OptimisticLockerInterceptor();
}

2、数据库必须有标志version字段,然后实体类中加注解

@Version
private Integer version;

注意:
    支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
	整数类型下 newVersion = oldVersion + 1
	newVersion 会回写到 entity 中
	仅支持 updateById(id) 与 update(entity, wrapper) 方法
	在 update(entity, wrapper) 方法下, wrapper 不能复用!!!

查询Select

id查询:

T t = mapper.selectById(id);

多个id批量查询

List<t> ts = mapper.selectBatchIds(Arrays.asList(1, 2, 3));

条件查询

HashMap<String, Object> map = new HashMap<>();
map.put("name", "Helen");
map.put("age", 18);
List<T> users = mapper.selectByMap(map);

Wrapper条件后面再说

.......

分页

配置bean
    /**分页插件*/
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
代码:
    Page<T> page = new Page<>(1,5);
    mkapper.selectPage(page, null);
    page.getRecords().forEach(System.out::println);
    System.out.println(page.getCurrent());
    System.out.println(page.getPages());
    System.out.println(page.getSize());
    System.out.println(page.getTotal());
    System.out.println(page.hasNext());
    System.out.println(page.hasPrevious());

删除Delete

操作

id删除

mapper.deleteById(id);

批量删除

int result=mapper.deleteBatchIds(Arrays.asList(8,9));

条件查询

HashMap<String, Object> map = new HashMap<>();
map.put("name", "Helen");
map.put("age", 18);
int result = mapper.deleteByMap(map);

Wrapper条件后面会说

...

逻辑删除

说起删除,应该分为两种:

逻辑删除:给定某一个标志代表该条数据已经被删除。

物理删除:真的删除了

1、给实体类字段上加注解

@TableLogic
private Integer deleted;

2、配置文件

# 此为默认配置,如果你的删除和未删除的标志不同则可以在此配置
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

3、配置bean

@Bean
public ISqlInjector sqlInjector() {
    return new LogicSqlInjector();
}

4、官网说明

# 说明:
	只对自动注入的sql起效:
# 插入: 不作限制
# 查找: 追加where条件过滤掉已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
# 更新: 追加where条件防止更新到已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
# 删除: 转变为 更新
# 例如:
    删除: update user set deleted=1 where id = 1 and deleted=0
    查找: select id,name,deleted from user where deleted=0
# 字段类型支持说明:
    支持所有数据类型(推荐使用 Integer,Boolean,LocalDateTime)
    如果数据库字段使用datetime,逻辑未删除值和已删除值支持配置为字符串null,另一个值支持配置为函数来获取值如now()
# 附录:
    逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。
    如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。
# 备注:
	字段值insert的时候,可以数据库默认值,可以自己set,使用自动填充功能

性能分析日志

配置插件

参数说明:

​ 参数:maxTime: SQL 执行最大时长,超过自动停止运行,有助于发现问题。

​ 参数:format: SQL是否格式化,默认false。

配置bean:

/**
 * SQL 执行性能分析插件
 * 开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长
 */
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启,prod不建议开启
public PerformanceInterceptor performanceInterceptor() {
    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(100);//ms,超过此处设置的ms则sql不执行
    performanceInterceptor.setFormat(true);
    return performanceInterceptor;
}

配置spring的dev环境

#环境设置:dev、test、prod
spring.profiles.active=dev

我们可以自定义对应开发、测试、生产环境不同的配置文件,然后不同环境下我们去使用不同的配置文件,可以在启动的时候添加参数,就可以不改变配置的情况下动态的选择环境,启动代码的时候-d,具体百度。

Wrapper介绍

介绍

	Wrapper:条件构造抽象类,最顶端父类
    	AbstractWrapper:用于查询条件封装,生成sql的where 条件
        	QueryWrapper:Entity对象封装操作类,不是用lambda语法
        	UpdateWrapper:Update条件封装,用于Entity对象更新操作
    	AbstractLambdaWrapper:Lambda语法使用Wrapper统一处理解析lambda获取column。
        	LambdaQueryWrapper:看名称也能明白就是用于Lambda语法使用的查询Wrapper
        	LambdaUpdateWrapper:Lambda更新封装Wrapper

一般我们使用QueryWrapper。

使用

ge、gt、le、lt、isNull、isNotNull:

	QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper
        .isNull("name")
        .ge("age", 12)
        .isNotNull("email");
    int result = userMapper.delete(queryWrapper);
    System.out.println("delete return count = " + result);
/**
ge:大于等于
gt:大于
le:小于等于
lt:小于
isNull:为空
isNotNull:不为空
*/

eq、ne:

/**
eq:相等
ne:不相等
*/

between、notBetween:

/**
between:在某一个边界
notBetween:不在某一个边界
*/

allEq:

/**
allEq:整个map的内容全都要全等
*/

like、notLike、likeLeft、likeRight:

/**
like:两边like,%a%
notLike:不like 
likeLeft:左边like,%a
likeRiter:右边like,a%
*/

太多了,就不一一列举了。。。。

posted on 2020-08-25 16:49  苦行僧DH  阅读(818)  评论(0编辑  收藏  举报