0


MyBatis-Plus

MyBatis-Plus

1、简介

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

润物无声

只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。

效率至上

只需简单配置,即可快速进行 CRUD 操作,从而节省大量时间。

丰富功能

热加载、代码生成、分页、性能分析等功能一应俱全。

2、创建并初始化数据库

2.1创建数据库

mybatis_plus

2.2创建 User 表

其对应的数据库 Schema 脚本如下:

CREATETABLEUSER(
    id BIGINT(20)NOTNULLCOMMENT'主键ID',
    NAME VARCHAR(30)NULLDEFAULTNULLCOMMENT'姓名',
    age INT(11)NULLDEFAULTNULLCOMMENT'年龄',
    email VARCHAR(50)NULLDEFAULTNULLCOMMENT'邮箱',PRIMARYKEY(id));

其对应的数据库 Data 脚本如下:

INSERTINTOuser(id, name, age, email)VALUES(1,'Jone',18,'[email protected]'),(2,'Jack',20,'[email protected]'),(3,'Tom',28,'[email protected]'),(4,'Sandy',21,'[email protected]'),(5,'Billie',24,'[email protected]');

3、确认idea配置

3.1 打开配置

3.2 Java编译器

3.3 项目和文件的编码

3.4 Maven配置

4、创建项目

4.1 初始化工程

使用 Spring Initializr 快速初始化一个 Spring Boot 工程

Group:com.aqrlmy

Artifact:mybatis_plus

版本:2.2.1.RELEASE

4.2 引入依赖

注意:引入 MyBatis-Plus 之后请不要再次引入 MyBatis,以避免因版本差异导致的问题。

<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.3.1</version></dependency><!--mysql依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--lombok用来简化实体类--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies>

4.3idea中安装lombok插件

4.3.1 idea2019版本

4.3.2 idea2018版本

5、编写代码

5.1 配置

在 application.properties 配置文件中添加 MySQL 数据库的相关配置:

spring boot 2.0(内置jdbc5驱动)

#mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

spring boot 2.1及以上(内置jdbc8驱动)

注意:driver和url的变化

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root

注意:

1、这里的 url 使用了 ?serverTimezone=GMT%2B8 后缀,因为8.0版本的jdbc驱动需要添加这个后缀,否则运行测试用例报告如下错误:

java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more

2、这里的 driver-class-name 使用了 com.mysql.cj.jdbc.Driver ,在 jdbc 8 中 建议使用这个驱动,否则运行测试用例的时候会有 WARN 信息

5.2 启动类

在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹

@SpringBootApplication@MapperScan("com.aqrlmy.demomptest.mapper")publicclassDemomptestApplication{publicstaticvoidmain(String[] args){SpringApplication.run(DemomptestApplication.class, args);}}

5.3 添加实体

创建包 entity 编写实体类 User.java(此处使用了 Lombok 简化代码)

@DatapublicclassUser{privateLong id;privateString name;privateInteger age;privateString email;}

查看编译结果

5.4 添加mapper

创建包 mapper 编写Mapper 接口: UserMapper.java

@RepositorypublicinterfaceUserMapperextendsBaseMapper<User>{}

5.5 测试

添加测试类,进行功能测试:

@SpringBootTestclassDemomptestApplicationTests{@AutowiredprivateUserMapper userMapper;@TestpublicvoidfindAll(){List<User> users = userMapper.selectList(null);System.out.println(users);}}

注意:

IDEA在 userMapper 处报错,因为找不到注入的对象,因为类是动态创建的,但是程序可以正确的执行。

为了避免报错,可以在 dao 层 的接口上添加 @Repository 注

通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能,甚至连 XML 文件都不用编写!

查看控制台输出:

5.6 查看sql输出日志

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

二、主键策略

1、插入操作

//添加@TestpublicvoidtestAdd(){User user =newUser();
    user.setName("lucy");
    user.setAge(20);
    user.setEmail("[email protected]");int insert = userMapper.insert(user);System.out.println(insert);}

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

2、MP的主键策略

2.1 ASSIGN_ID

MyBatis-Plus默认的主键策略是:ASSIGN_ID (使用了雪花算法)

@TableId(type =IdType.ASSIGN_ID)privateString id;

雪花算法:分布式ID生成器

雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。

核心思想:

长度共64bit(一个long型)。

首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。

41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 - 开始时间截),结果约等于69.73年。

10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。

12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。

优点:整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。

2.2 AUTO 自增策略

需要在创建数据表的时候设置主键自增

实体字段中配置 @TableId(type = IdType.AUTO)

@TableId(type =IdType.AUTO)privateLong id;

要想影响所有实体的配置,可以设置全局主键配置

#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto

三、自动填充和乐观锁

1、更新操作

注意:update时生成的sql自动是动态sql:UPDATE user SET age=? WHERE id=?

//修改@TestpublicvoidtestUpdate(){User user =newUser();
    user.setId(1340868235401764865L);
    user.setName("lucymary");int count = userMapper.updateById(user);System.out.println(count);}

2、自动填充

需求描述:

项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。

我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作

2.1数据库修改

在User表中添加datetime类型的新的字段 create_time、update_time

2.2实体类修改

实体上增加字段并添加自动填充注解

@TableField(fill =FieldFill.INSERT)privateDate createTime;//create_time@TableField(fill =FieldFill.INSERT_UPDATE)privateDate updateTime;//update_time

2.3实现元对象处理器接口

注意:不要忘记添加 @Component 注解

@ComponentpublicclassMyMetaObjectHandlerimplementsMetaObjectHandler{//mp执行添加操作,这个方法执行@OverridepublicvoidinsertFill(MetaObject metaObject){this.setFieldValByName("createTime",newDate(),metaObject);this.setFieldValByName("updateTime",newDate(),metaObject);}//mp执行修改操作,这个方法执行@OverridepublicvoidupdateFill(MetaObject metaObject){this.setFieldValByName("updateTime",newDate(),metaObject);}}

3、乐观锁

3.1场景

主要适用场景:当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新

乐观锁实现方式:

取出记录时,获取当前version

更新时,带上这个version

执行更新时, set version = newVersion where version = oldVersion

如果version不对,就更新失败

接下来介绍如何在Mybatis-Plus项目中,使用乐观锁:

4、乐观锁实现流程

4.1修改实体类

添加 @Version 注解

@VersionprivateInteger version;

4.2创建配置文件

创建包config,创建文件MybatisPlusConfig.java

此时可以删除主类中的 @MapperScan 扫描注解

@Configuration@MapperScan("com.aqrlmy.demomptest.mapper")publicclassMpConfig{/**
     * 乐观锁插件
     */@BeanpublicOptimisticLockerInterceptoroptimisticLockerInterceptor(){returnnewOptimisticLockerInterceptor();}}

4.3注册乐观锁插件

在 MybatisPlusConfig 中注册 Bean

/**
* 乐观锁插件
*/@BeanpublicOptimisticLockerInterceptoroptimisticLockerInterceptor(){returnnewOptimisticLockerInterceptor();}

四、查询

1、查询

1.1通过多个id批量查询

完成了动态sql的foreach的功能

//多个id批量查询@TestpublicvoidtestSelect1(){List<User> users = userMapper.selectBatchIds(Arrays.asList(1,2,3));System.out.println(users);}

1.2简单的条件查询

通过map封装查询条件

注意:map中的key对应数据库中的列名。如:数据库user_id,实体类是userId,这时map的key需要填写user_id

//简单条件查询@TestpublicvoidtestSelect2(){Map<String,Object> columnMap =newHashMap<>();
    columnMap.put("name","Jack");
    columnMap.put("age",20);List<User> users = userMapper.selectByMap(columnMap);System.out.println(users);}

2、分页

2.1分页插件

MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能

2.1.1添加分页插件

配置类中添加@Bean配置

/**
 * 分页插件
 */@BeanpublicPaginationInterceptorpaginationInterceptor(){returnnewPaginationInterceptor();}

2.1.2测试selectPage分页

测试:最终通过page对象获取相关数据

//分页查询@TestpublicvoidtestSelectPage(){Page<User> page =newPage(1,3);Page<User> userPage = userMapper.selectPage(page,null);//返回对象得到分页所有数据long pages = userPage.getPages();//总页数long current = userPage.getCurrent();//当前页List<User> records = userPage.getRecords();//查询数据集合long total = userPage.getTotal();//总记录数boolean hasNext = userPage.hasNext();//下一页boolean hasPrevious = userPage.hasPrevious();//上一页System.out.println(pages);System.out.println(current);System.out.println(records);System.out.println(total);System.out.println(hasNext);System.out.println(hasPrevious);}

2.2测试selectMapsPage分页

当指定了特定的查询列时,希望分页结果列表只返回被查询的列,而不是很多null值

测试selectMapsPage分页:结果集是Map

@TestpublicvoidtestSelectMapsPage(){//Page不需要泛型Page<Map<String,Object>> page = newPage<>(1,5);Page<Map<String,Object>> pageParam = userMapper.selectMapsPage(page,null);List<Map<String,Object>> records = pageParam.getRecords();
records.forEach(System.out::println);System.out.println(pageParam.getCurrent());System.out.println(pageParam.getPages());System.out.println(pageParam.getSize());System.out.println(pageParam.getTotal());System.out.println(pageParam.hasNext());System.out.println(pageParam.hasPrevious());}

五、删除与逻辑删除

1、删除

1.1根据id删除记录

@TestpublicvoidtestDeleteById(){int result = userMapper.deleteById(5L);
system.out.println(result);}

1.2批量删除

@TestpublicvoidtestDeleteBatchIds(){int result = userMapper.deleteBatchIds(Arrays.asList(8,9,10));
system.out.println(result);}

1.3简单条件删除

@TestpublicvoidtestDeleteByMap(){HashMap<String,Object> map =newHashMap<>();
map.put("name","Helen");
map.put("age",18);int result = userMapper.deleteByMap(map);
system.out.println(result);}

2、逻辑删除

2.1物理删除和逻辑删除

物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据

逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

逻辑删除的使用场景:

可以进行数据恢复

有关联数据,不便删除

2.2 逻辑删除实现流程

2.2.1数据库修改

添加 deleted字段

ALTERTABLE `user`ADDCOLUMN`deleted`booleanDEFAULTfalse

2.2.2实体类修改

添加deleted 字段,并加上 @TableLogic 注解

@TableLogicprivateInteger deleted;

2.2.3配置(可选)

application.properties 加入以下配置,此为默认值,如果你的默认值和mp默认的一样,该配置可无

mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

2.2.4 测试

测试后发现,数据并没有被删除,deleted字段的值由0变成了1

测试后分析打印的sql语句,是一条update

注意:被删除前,数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作

@TestpublicvoidtestLogicDelete(){int result = userMapper.deleteById(1L);
system.out.println(result);}

2.2.5测试逻辑删除后的查询

MyBatis Plus中查询操作也会自动添加逻辑删除字段的判断

@TestpublicvoidtestLogicDeleteSelect(){List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);}

六、条件构造器和常用接口

wapper介绍

Wrapper : 条件构造抽象类,最顶端父类

AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件

QueryWrapper : 查询条件封装

UpdateWrapper : Update 条件封装

AbstractLambdaWrapper : 使用Lambda 语法

LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper

LambdaUpdateWrapper : Lambda 更新封装Wrapper

@SpringBootTest
publicclassQueryWrapperTests {@Autowired
privateUserMapperuserMapper;}

2、测试用例

2.1 ge、gt、le、lt、isNull、isNotNull

@TestpublicvoidtestQuery(){QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper
        .isNull("name").ge("age",12).isNotNull("email");int result = userMapper.delete(queryWrapper);System.out.println("delete return count = "+ result);}

2.2 eq、ne

注意:seletOne()返回的是一条实体记录,当出现多条时会报错

@TestpublicvoidtestSelectOne(){QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper.eq("name","Tom");Useruser= userMapper.selectOne(queryWrapper);//只能返回一条记录,多余一条则抛出异常System.out.println(user);}

2.3 between、notBetween

包含大小边界

@TestpublicvoidtestSelectCount(){QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper.between("age",20,30);Integer count = userMapper.selectCount(queryWrapper);//返回数据数量System.out.println(count);}

2.4 like、notLike、likeLeft、likeRight

selectMaps()返回Map集合列表,通常配合select()使用

@TestpublicvoidtestSelectMaps(){QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper
        .select("name","age").like("name","e").likeRight("email","5");List<Map<String,Object>>maps = userMapper.selectMaps(queryWrapper);//返回值是Map列表
maps.forEach(System.out::println);}

2.5 orderBy、orderByDesc、orderByAsc

@TestpublicvoidtestSelectListOrderBy(){QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper.orderByDesc("age","id");List<User>users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);}

查询方式

查询方式说明setSqlSelect设置 SELECT 查询字段whereWHERE 语句,拼接 + WHERE 条件andAND 语句,拼接 + AND 字段=值andNewAND 语句,拼接 + AND (字段=值)orOR 语句,拼接 + OR 字段=值orNewOR 语句,拼接 + OR (字段=值)eq等于=allEq基于 map 内容等于=ne不等于<>gt大于>ge大于等于>=lt小于<le小于等于<=like模糊查询 LIKEnotLike模糊查询 NOT LIKEinIN 查询notInNOT IN 查询isNullNULL 值查询isNotNullIS NOT NULLgroupBy分组 GROUP BYhavingHAVING 关键词orderBy排序 ORDER BYorderAscASC 排序 ORDER BYorderDescDESC 排序 ORDER BYexistsEXISTS 条件语句notExistsNOT EXISTS 条件语句betweenBETWEEN 条件语句notBetweenNOT BETWEEN 条件语句addFilter自由拼接 SQLlast拼接在最后,例如:last(“LIMIT 1”)


本文转载自: https://blog.csdn.net/LMY0210/article/details/128150472
版权归原作者 aqr-lmy 所有, 如有侵权,请联系我们删除。

“MyBatis-Plus”的评论:

还没有评论